├── .env.example ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── local ├── api │ └── Dockerfile ├── db │ └── Dockerfile ├── docker-compose.yml └── scripts │ ├── clear_permission │ ├── exec_init_db │ ├── init_db │ └── migrate ├── migrations ├── 20220121053505_users.down.sql ├── 20220121053505_users.up.sql ├── 20220121060109_categories.down.sql ├── 20220121060109_categories.up.sql ├── 20220121060224_posts.down.sql └── 20220121060224_posts.up.sql ├── openapi ├── openapi.yaml ├── paths │ ├── categories │ │ ├── add.yaml │ │ └── index.yaml │ ├── posts │ │ ├── add.yaml │ │ └── index.yaml │ └── users │ │ ├── add.yaml │ │ ├── edit │ │ └── img │ │ │ └── profile.yaml │ │ ├── index.yaml │ │ └── view.yaml └── schemas │ ├── category.yaml │ ├── index.yaml │ ├── post.yaml │ └── user.yaml └── src ├── bootstrap └── mod.rs ├── controllers ├── categories.rs ├── middleware │ └── mod.rs ├── mod.rs ├── posts.rs └── users.rs ├── db ├── mod.rs └── postgres │ └── mod.rs ├── error └── mod.rs ├── main.rs ├── models ├── category.rs ├── mod.rs ├── post.rs └── user.rs ├── repositories ├── category.rs ├── mod.rs ├── post.rs └── user.rs ├── router └── mod.rs ├── services ├── img_upload.rs └── mod.rs ├── tests ├── fixture │ ├── category.rs │ ├── mod.rs │ ├── post.rs │ └── user.rs ├── mod.rs └── repositories │ └── mod.rs └── usecases ├── categories.rs ├── mod.rs ├── posts.rs └── users.rs /.env.example: -------------------------------------------------------------------------------- 1 | DATABASE_URL=postgres://user:password@db/database 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .env -------------------------------------------------------------------------------- /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 = "adler" 7 | version = "1.0.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 10 | 11 | [[package]] 12 | name = "adler32" 13 | version = "1.2.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" 16 | 17 | [[package]] 18 | name = "ahash" 19 | version = "0.7.6" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" 22 | dependencies = [ 23 | "getrandom", 24 | "once_cell", 25 | "version_check", 26 | ] 27 | 28 | [[package]] 29 | name = "aho-corasick" 30 | version = "0.7.18" 31 | source = "registry+https://github.com/rust-lang/crates.io-index" 32 | checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" 33 | dependencies = [ 34 | "memchr", 35 | ] 36 | 37 | [[package]] 38 | name = "ansi_term" 39 | version = "0.12.1" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" 42 | dependencies = [ 43 | "winapi", 44 | ] 45 | 46 | [[package]] 47 | name = "anyhow" 48 | version = "1.0.53" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "94a45b455c14666b85fc40a019e8ab9eb75e3a124e05494f5397122bc9eb06e0" 51 | 52 | [[package]] 53 | name = "async-trait" 54 | version = "0.1.52" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3" 57 | dependencies = [ 58 | "proc-macro2", 59 | "quote", 60 | "syn", 61 | ] 62 | 63 | [[package]] 64 | name = "atoi" 65 | version = "0.4.0" 66 | source = "registry+https://github.com/rust-lang/crates.io-index" 67 | checksum = "616896e05fc0e2649463a93a15183c6a16bf03413a7af88ef1285ddedfa9cda5" 68 | dependencies = [ 69 | "num-traits", 70 | ] 71 | 72 | [[package]] 73 | name = "autocfg" 74 | version = "1.0.1" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 77 | 78 | [[package]] 79 | name = "axum" 80 | version = "0.4.4" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | checksum = "310a147401c66e79fc78636e4db63ac68cd6acb9ece056de806ea173a15bce32" 83 | dependencies = [ 84 | "async-trait", 85 | "axum-core", 86 | "bitflags", 87 | "bytes", 88 | "futures-util", 89 | "http", 90 | "http-body", 91 | "hyper", 92 | "matchit", 93 | "memchr", 94 | "mime", 95 | "multer", 96 | "percent-encoding", 97 | "pin-project-lite", 98 | "serde", 99 | "serde_json", 100 | "serde_urlencoded", 101 | "sync_wrapper", 102 | "tokio", 103 | "tokio-util", 104 | "tower", 105 | "tower-http", 106 | "tower-layer", 107 | "tower-service", 108 | ] 109 | 110 | [[package]] 111 | name = "axum-core" 112 | version = "0.1.1" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | checksum = "1ca6c0b218388a7ed6a8d25e94f7dea5498daaa4fd8c711fb3ff166041b06fda" 115 | dependencies = [ 116 | "async-trait", 117 | "bytes", 118 | "futures-util", 119 | "http", 120 | "http-body", 121 | "mime", 122 | ] 123 | 124 | [[package]] 125 | name = "base64" 126 | version = "0.13.0" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" 129 | 130 | [[package]] 131 | name = "bit_field" 132 | version = "0.10.1" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4" 135 | 136 | [[package]] 137 | name = "bitflags" 138 | version = "1.3.2" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 141 | 142 | [[package]] 143 | name = "block-buffer" 144 | version = "0.9.0" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" 147 | dependencies = [ 148 | "generic-array", 149 | ] 150 | 151 | [[package]] 152 | name = "bumpalo" 153 | version = "3.9.1" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" 156 | 157 | [[package]] 158 | name = "bytemuck" 159 | version = "1.7.3" 160 | source = "registry+https://github.com/rust-lang/crates.io-index" 161 | checksum = "439989e6b8c38d1b6570a384ef1e49c8848128f5a97f3914baef02920842712f" 162 | 163 | [[package]] 164 | name = "byteorder" 165 | version = "1.4.3" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 168 | 169 | [[package]] 170 | name = "bytes" 171 | version = "1.1.0" 172 | source = "registry+https://github.com/rust-lang/crates.io-index" 173 | checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" 174 | 175 | [[package]] 176 | name = "cc" 177 | version = "1.0.72" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" 180 | 181 | [[package]] 182 | name = "cfg-if" 183 | version = "1.0.0" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 186 | 187 | [[package]] 188 | name = "color_quant" 189 | version = "1.1.0" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" 192 | 193 | [[package]] 194 | name = "core-foundation" 195 | version = "0.9.2" 196 | source = "registry+https://github.com/rust-lang/crates.io-index" 197 | checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3" 198 | dependencies = [ 199 | "core-foundation-sys", 200 | "libc", 201 | ] 202 | 203 | [[package]] 204 | name = "core-foundation-sys" 205 | version = "0.8.3" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" 208 | 209 | [[package]] 210 | name = "cpufeatures" 211 | version = "0.2.1" 212 | source = "registry+https://github.com/rust-lang/crates.io-index" 213 | checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" 214 | dependencies = [ 215 | "libc", 216 | ] 217 | 218 | [[package]] 219 | name = "crc" 220 | version = "2.1.0" 221 | source = "registry+https://github.com/rust-lang/crates.io-index" 222 | checksum = "49fc9a695bca7f35f5f4c15cddc84415f66a74ea78eef08e90c5024f2b540e23" 223 | dependencies = [ 224 | "crc-catalog", 225 | ] 226 | 227 | [[package]] 228 | name = "crc-catalog" 229 | version = "1.1.1" 230 | source = "registry+https://github.com/rust-lang/crates.io-index" 231 | checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403" 232 | 233 | [[package]] 234 | name = "crc32fast" 235 | version = "1.3.2" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" 238 | dependencies = [ 239 | "cfg-if", 240 | ] 241 | 242 | [[package]] 243 | name = "crossbeam-channel" 244 | version = "0.5.2" 245 | source = "registry+https://github.com/rust-lang/crates.io-index" 246 | checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa" 247 | dependencies = [ 248 | "cfg-if", 249 | "crossbeam-utils", 250 | ] 251 | 252 | [[package]] 253 | name = "crossbeam-deque" 254 | version = "0.8.1" 255 | source = "registry+https://github.com/rust-lang/crates.io-index" 256 | checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" 257 | dependencies = [ 258 | "cfg-if", 259 | "crossbeam-epoch", 260 | "crossbeam-utils", 261 | ] 262 | 263 | [[package]] 264 | name = "crossbeam-epoch" 265 | version = "0.9.7" 266 | source = "registry+https://github.com/rust-lang/crates.io-index" 267 | checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9" 268 | dependencies = [ 269 | "cfg-if", 270 | "crossbeam-utils", 271 | "lazy_static", 272 | "memoffset", 273 | "scopeguard", 274 | ] 275 | 276 | [[package]] 277 | name = "crossbeam-queue" 278 | version = "0.3.3" 279 | source = "registry+https://github.com/rust-lang/crates.io-index" 280 | checksum = "b979d76c9fcb84dffc80a73f7290da0f83e4c95773494674cb44b76d13a7a110" 281 | dependencies = [ 282 | "cfg-if", 283 | "crossbeam-utils", 284 | ] 285 | 286 | [[package]] 287 | name = "crossbeam-utils" 288 | version = "0.8.6" 289 | source = "registry+https://github.com/rust-lang/crates.io-index" 290 | checksum = "cfcae03edb34f947e64acdb1c33ec169824e20657e9ecb61cef6c8c74dcb8120" 291 | dependencies = [ 292 | "cfg-if", 293 | "lazy_static", 294 | ] 295 | 296 | [[package]] 297 | name = "crypto-mac" 298 | version = "0.11.1" 299 | source = "registry+https://github.com/rust-lang/crates.io-index" 300 | checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" 301 | dependencies = [ 302 | "generic-array", 303 | "subtle", 304 | ] 305 | 306 | [[package]] 307 | name = "deflate" 308 | version = "0.9.1" 309 | source = "registry+https://github.com/rust-lang/crates.io-index" 310 | checksum = "5f95bf05dffba6e6cce8dfbb30def788154949ccd9aed761b472119c21e01c70" 311 | dependencies = [ 312 | "adler32", 313 | ] 314 | 315 | [[package]] 316 | name = "deflate" 317 | version = "1.0.0" 318 | source = "registry+https://github.com/rust-lang/crates.io-index" 319 | checksum = "c86f7e25f518f4b81808a2cf1c50996a61f5c2eb394b2393bd87f2a4780a432f" 320 | dependencies = [ 321 | "adler32", 322 | ] 323 | 324 | [[package]] 325 | name = "difflib" 326 | version = "0.4.0" 327 | source = "registry+https://github.com/rust-lang/crates.io-index" 328 | checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" 329 | 330 | [[package]] 331 | name = "digest" 332 | version = "0.9.0" 333 | source = "registry+https://github.com/rust-lang/crates.io-index" 334 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 335 | dependencies = [ 336 | "generic-array", 337 | ] 338 | 339 | [[package]] 340 | name = "dirs" 341 | version = "4.0.0" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" 344 | dependencies = [ 345 | "dirs-sys", 346 | ] 347 | 348 | [[package]] 349 | name = "dirs-sys" 350 | version = "0.3.6" 351 | source = "registry+https://github.com/rust-lang/crates.io-index" 352 | checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" 353 | dependencies = [ 354 | "libc", 355 | "redox_users", 356 | "winapi", 357 | ] 358 | 359 | [[package]] 360 | name = "dotenv" 361 | version = "0.15.0" 362 | source = "registry+https://github.com/rust-lang/crates.io-index" 363 | checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" 364 | 365 | [[package]] 366 | name = "downcast" 367 | version = "0.11.0" 368 | source = "registry+https://github.com/rust-lang/crates.io-index" 369 | checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" 370 | 371 | [[package]] 372 | name = "either" 373 | version = "1.6.1" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 376 | 377 | [[package]] 378 | name = "encoding" 379 | version = "0.2.33" 380 | source = "registry+https://github.com/rust-lang/crates.io-index" 381 | checksum = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec" 382 | dependencies = [ 383 | "encoding-index-japanese", 384 | "encoding-index-korean", 385 | "encoding-index-simpchinese", 386 | "encoding-index-singlebyte", 387 | "encoding-index-tradchinese", 388 | ] 389 | 390 | [[package]] 391 | name = "encoding-index-japanese" 392 | version = "1.20141219.5" 393 | source = "registry+https://github.com/rust-lang/crates.io-index" 394 | checksum = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91" 395 | dependencies = [ 396 | "encoding_index_tests", 397 | ] 398 | 399 | [[package]] 400 | name = "encoding-index-korean" 401 | version = "1.20141219.5" 402 | source = "registry+https://github.com/rust-lang/crates.io-index" 403 | checksum = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81" 404 | dependencies = [ 405 | "encoding_index_tests", 406 | ] 407 | 408 | [[package]] 409 | name = "encoding-index-simpchinese" 410 | version = "1.20141219.5" 411 | source = "registry+https://github.com/rust-lang/crates.io-index" 412 | checksum = "d87a7194909b9118fc707194baa434a4e3b0fb6a5a757c73c3adb07aa25031f7" 413 | dependencies = [ 414 | "encoding_index_tests", 415 | ] 416 | 417 | [[package]] 418 | name = "encoding-index-singlebyte" 419 | version = "1.20141219.5" 420 | source = "registry+https://github.com/rust-lang/crates.io-index" 421 | checksum = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a" 422 | dependencies = [ 423 | "encoding_index_tests", 424 | ] 425 | 426 | [[package]] 427 | name = "encoding-index-tradchinese" 428 | version = "1.20141219.5" 429 | source = "registry+https://github.com/rust-lang/crates.io-index" 430 | checksum = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18" 431 | dependencies = [ 432 | "encoding_index_tests", 433 | ] 434 | 435 | [[package]] 436 | name = "encoding_index_tests" 437 | version = "0.1.4" 438 | source = "registry+https://github.com/rust-lang/crates.io-index" 439 | checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569" 440 | 441 | [[package]] 442 | name = "encoding_rs" 443 | version = "0.8.30" 444 | source = "registry+https://github.com/rust-lang/crates.io-index" 445 | checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" 446 | dependencies = [ 447 | "cfg-if", 448 | ] 449 | 450 | [[package]] 451 | name = "exr" 452 | version = "1.4.1" 453 | source = "registry+https://github.com/rust-lang/crates.io-index" 454 | checksum = "d4badb9489a465cb2c555af1f00f0bfd8cecd6fc12ac11da9d5b40c5dd5f0200" 455 | dependencies = [ 456 | "bit_field", 457 | "deflate 1.0.0", 458 | "flume", 459 | "half", 460 | "inflate", 461 | "lebe", 462 | "smallvec", 463 | "threadpool", 464 | ] 465 | 466 | [[package]] 467 | name = "fastrand" 468 | version = "1.7.0" 469 | source = "registry+https://github.com/rust-lang/crates.io-index" 470 | checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" 471 | dependencies = [ 472 | "instant", 473 | ] 474 | 475 | [[package]] 476 | name = "flate2" 477 | version = "1.0.22" 478 | source = "registry+https://github.com/rust-lang/crates.io-index" 479 | checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" 480 | dependencies = [ 481 | "cfg-if", 482 | "crc32fast", 483 | "libc", 484 | "miniz_oxide", 485 | ] 486 | 487 | [[package]] 488 | name = "float-cmp" 489 | version = "0.9.0" 490 | source = "registry+https://github.com/rust-lang/crates.io-index" 491 | checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" 492 | dependencies = [ 493 | "num-traits", 494 | ] 495 | 496 | [[package]] 497 | name = "flume" 498 | version = "0.10.10" 499 | source = "registry+https://github.com/rust-lang/crates.io-index" 500 | checksum = "5d04dafd11240188e146b6f6476a898004cace3be31d4ec5e08e216bf4947ac0" 501 | dependencies = [ 502 | "futures-core", 503 | "futures-sink", 504 | "nanorand", 505 | "pin-project", 506 | "spin", 507 | ] 508 | 509 | [[package]] 510 | name = "fnv" 511 | version = "1.0.7" 512 | source = "registry+https://github.com/rust-lang/crates.io-index" 513 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 514 | 515 | [[package]] 516 | name = "foreign-types" 517 | version = "0.3.2" 518 | source = "registry+https://github.com/rust-lang/crates.io-index" 519 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 520 | dependencies = [ 521 | "foreign-types-shared", 522 | ] 523 | 524 | [[package]] 525 | name = "foreign-types-shared" 526 | version = "0.1.1" 527 | source = "registry+https://github.com/rust-lang/crates.io-index" 528 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 529 | 530 | [[package]] 531 | name = "form_urlencoded" 532 | version = "1.0.1" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" 535 | dependencies = [ 536 | "matches", 537 | "percent-encoding", 538 | ] 539 | 540 | [[package]] 541 | name = "fragile" 542 | version = "1.1.0" 543 | source = "registry+https://github.com/rust-lang/crates.io-index" 544 | checksum = "8da1b8f89c5b5a5b7e59405cfcf0bb9588e5ed19f0b57a4cd542bbba3f164a6d" 545 | 546 | [[package]] 547 | name = "futures-channel" 548 | version = "0.3.19" 549 | source = "registry+https://github.com/rust-lang/crates.io-index" 550 | checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b" 551 | dependencies = [ 552 | "futures-core", 553 | "futures-sink", 554 | ] 555 | 556 | [[package]] 557 | name = "futures-core" 558 | version = "0.3.19" 559 | source = "registry+https://github.com/rust-lang/crates.io-index" 560 | checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7" 561 | 562 | [[package]] 563 | name = "futures-intrusive" 564 | version = "0.4.0" 565 | source = "registry+https://github.com/rust-lang/crates.io-index" 566 | checksum = "62007592ac46aa7c2b6416f7deb9a8a8f63a01e0f1d6e1787d5630170db2b63e" 567 | dependencies = [ 568 | "futures-core", 569 | "lock_api", 570 | "parking_lot", 571 | ] 572 | 573 | [[package]] 574 | name = "futures-sink" 575 | version = "0.3.19" 576 | source = "registry+https://github.com/rust-lang/crates.io-index" 577 | checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508" 578 | 579 | [[package]] 580 | name = "futures-task" 581 | version = "0.3.19" 582 | source = "registry+https://github.com/rust-lang/crates.io-index" 583 | checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72" 584 | 585 | [[package]] 586 | name = "futures-util" 587 | version = "0.3.19" 588 | source = "registry+https://github.com/rust-lang/crates.io-index" 589 | checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164" 590 | dependencies = [ 591 | "futures-core", 592 | "futures-sink", 593 | "futures-task", 594 | "pin-project-lite", 595 | "pin-utils", 596 | ] 597 | 598 | [[package]] 599 | name = "generic-array" 600 | version = "0.14.5" 601 | source = "registry+https://github.com/rust-lang/crates.io-index" 602 | checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" 603 | dependencies = [ 604 | "typenum", 605 | "version_check", 606 | ] 607 | 608 | [[package]] 609 | name = "getrandom" 610 | version = "0.2.4" 611 | source = "registry+https://github.com/rust-lang/crates.io-index" 612 | checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" 613 | dependencies = [ 614 | "cfg-if", 615 | "js-sys", 616 | "libc", 617 | "wasi", 618 | "wasm-bindgen", 619 | ] 620 | 621 | [[package]] 622 | name = "gif" 623 | version = "0.11.3" 624 | source = "registry+https://github.com/rust-lang/crates.io-index" 625 | checksum = "c3a7187e78088aead22ceedeee99779455b23fc231fe13ec443f99bb71694e5b" 626 | dependencies = [ 627 | "color_quant", 628 | "weezl", 629 | ] 630 | 631 | [[package]] 632 | name = "half" 633 | version = "1.8.2" 634 | source = "registry+https://github.com/rust-lang/crates.io-index" 635 | checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" 636 | 637 | [[package]] 638 | name = "hashbrown" 639 | version = "0.11.2" 640 | source = "registry+https://github.com/rust-lang/crates.io-index" 641 | checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" 642 | dependencies = [ 643 | "ahash", 644 | ] 645 | 646 | [[package]] 647 | name = "hashlink" 648 | version = "0.7.0" 649 | source = "registry+https://github.com/rust-lang/crates.io-index" 650 | checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" 651 | dependencies = [ 652 | "hashbrown", 653 | ] 654 | 655 | [[package]] 656 | name = "heck" 657 | version = "0.3.3" 658 | source = "registry+https://github.com/rust-lang/crates.io-index" 659 | checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" 660 | dependencies = [ 661 | "unicode-segmentation", 662 | ] 663 | 664 | [[package]] 665 | name = "hermit-abi" 666 | version = "0.1.19" 667 | source = "registry+https://github.com/rust-lang/crates.io-index" 668 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 669 | dependencies = [ 670 | "libc", 671 | ] 672 | 673 | [[package]] 674 | name = "hex" 675 | version = "0.4.3" 676 | source = "registry+https://github.com/rust-lang/crates.io-index" 677 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 678 | 679 | [[package]] 680 | name = "hmac" 681 | version = "0.11.0" 682 | source = "registry+https://github.com/rust-lang/crates.io-index" 683 | checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" 684 | dependencies = [ 685 | "crypto-mac", 686 | "digest", 687 | ] 688 | 689 | [[package]] 690 | name = "http" 691 | version = "0.2.6" 692 | source = "registry+https://github.com/rust-lang/crates.io-index" 693 | checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03" 694 | dependencies = [ 695 | "bytes", 696 | "fnv", 697 | "itoa 1.0.1", 698 | ] 699 | 700 | [[package]] 701 | name = "http-body" 702 | version = "0.4.4" 703 | source = "registry+https://github.com/rust-lang/crates.io-index" 704 | checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" 705 | dependencies = [ 706 | "bytes", 707 | "http", 708 | "pin-project-lite", 709 | ] 710 | 711 | [[package]] 712 | name = "http-range-header" 713 | version = "0.3.0" 714 | source = "registry+https://github.com/rust-lang/crates.io-index" 715 | checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" 716 | 717 | [[package]] 718 | name = "httparse" 719 | version = "1.5.1" 720 | source = "registry+https://github.com/rust-lang/crates.io-index" 721 | checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" 722 | 723 | [[package]] 724 | name = "httpdate" 725 | version = "1.0.2" 726 | source = "registry+https://github.com/rust-lang/crates.io-index" 727 | checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" 728 | 729 | [[package]] 730 | name = "hyper" 731 | version = "0.14.16" 732 | source = "registry+https://github.com/rust-lang/crates.io-index" 733 | checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55" 734 | dependencies = [ 735 | "bytes", 736 | "futures-channel", 737 | "futures-core", 738 | "futures-util", 739 | "http", 740 | "http-body", 741 | "httparse", 742 | "httpdate", 743 | "itoa 0.4.8", 744 | "pin-project-lite", 745 | "socket2", 746 | "tokio", 747 | "tower-service", 748 | "tracing", 749 | "want", 750 | ] 751 | 752 | [[package]] 753 | name = "idna" 754 | version = "0.2.3" 755 | source = "registry+https://github.com/rust-lang/crates.io-index" 756 | checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" 757 | dependencies = [ 758 | "matches", 759 | "unicode-bidi", 760 | "unicode-normalization", 761 | ] 762 | 763 | [[package]] 764 | name = "image" 765 | version = "0.24.0" 766 | source = "registry+https://github.com/rust-lang/crates.io-index" 767 | checksum = "e94ac3d41f882c624a82d7945952032388488681f45f9d4077999a6c85688d61" 768 | dependencies = [ 769 | "bytemuck", 770 | "byteorder", 771 | "color_quant", 772 | "exr", 773 | "gif", 774 | "jpeg-decoder 0.2.1", 775 | "num-iter", 776 | "num-rational", 777 | "num-traits", 778 | "png", 779 | "scoped_threadpool", 780 | "tiff", 781 | ] 782 | 783 | [[package]] 784 | name = "indexmap" 785 | version = "1.8.0" 786 | source = "registry+https://github.com/rust-lang/crates.io-index" 787 | checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" 788 | dependencies = [ 789 | "autocfg", 790 | "hashbrown", 791 | ] 792 | 793 | [[package]] 794 | name = "inflate" 795 | version = "0.4.5" 796 | source = "registry+https://github.com/rust-lang/crates.io-index" 797 | checksum = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff" 798 | dependencies = [ 799 | "adler32", 800 | ] 801 | 802 | [[package]] 803 | name = "instant" 804 | version = "0.1.12" 805 | source = "registry+https://github.com/rust-lang/crates.io-index" 806 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 807 | dependencies = [ 808 | "cfg-if", 809 | ] 810 | 811 | [[package]] 812 | name = "itertools" 813 | version = "0.10.3" 814 | source = "registry+https://github.com/rust-lang/crates.io-index" 815 | checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" 816 | dependencies = [ 817 | "either", 818 | ] 819 | 820 | [[package]] 821 | name = "itoa" 822 | version = "0.4.8" 823 | source = "registry+https://github.com/rust-lang/crates.io-index" 824 | checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" 825 | 826 | [[package]] 827 | name = "itoa" 828 | version = "1.0.1" 829 | source = "registry+https://github.com/rust-lang/crates.io-index" 830 | checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" 831 | 832 | [[package]] 833 | name = "jpeg-decoder" 834 | version = "0.1.22" 835 | source = "registry+https://github.com/rust-lang/crates.io-index" 836 | checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2" 837 | 838 | [[package]] 839 | name = "jpeg-decoder" 840 | version = "0.2.1" 841 | source = "registry+https://github.com/rust-lang/crates.io-index" 842 | checksum = "fbcf0244f6597be39ab8d9203f574cafb529ae8c698afa2182f7b3c3205a4a9c" 843 | dependencies = [ 844 | "rayon", 845 | ] 846 | 847 | [[package]] 848 | name = "js-sys" 849 | version = "0.3.56" 850 | source = "registry+https://github.com/rust-lang/crates.io-index" 851 | checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" 852 | dependencies = [ 853 | "wasm-bindgen", 854 | ] 855 | 856 | [[package]] 857 | name = "kamadak-exif" 858 | version = "0.5.4" 859 | source = "registry+https://github.com/rust-lang/crates.io-index" 860 | checksum = "70494964492bf8e491eb3951c5d70c9627eb7100ede6cc56d748b9a3f302cfb6" 861 | dependencies = [ 862 | "mutate_once", 863 | ] 864 | 865 | [[package]] 866 | name = "lazy_static" 867 | version = "1.4.0" 868 | source = "registry+https://github.com/rust-lang/crates.io-index" 869 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 870 | 871 | [[package]] 872 | name = "lebe" 873 | version = "0.5.1" 874 | source = "registry+https://github.com/rust-lang/crates.io-index" 875 | checksum = "7efd1d698db0759e6ef11a7cd44407407399a910c774dd804c64c032da7826ff" 876 | 877 | [[package]] 878 | name = "libc" 879 | version = "0.2.113" 880 | source = "registry+https://github.com/rust-lang/crates.io-index" 881 | checksum = "eef78b64d87775463c549fbd80e19249ef436ea3bf1de2a1eb7e717ec7fab1e9" 882 | 883 | [[package]] 884 | name = "lock_api" 885 | version = "0.4.5" 886 | source = "registry+https://github.com/rust-lang/crates.io-index" 887 | checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" 888 | dependencies = [ 889 | "scopeguard", 890 | ] 891 | 892 | [[package]] 893 | name = "log" 894 | version = "0.4.14" 895 | source = "registry+https://github.com/rust-lang/crates.io-index" 896 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 897 | dependencies = [ 898 | "cfg-if", 899 | ] 900 | 901 | [[package]] 902 | name = "matchers" 903 | version = "0.1.0" 904 | source = "registry+https://github.com/rust-lang/crates.io-index" 905 | checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" 906 | dependencies = [ 907 | "regex-automata", 908 | ] 909 | 910 | [[package]] 911 | name = "matches" 912 | version = "0.1.9" 913 | source = "registry+https://github.com/rust-lang/crates.io-index" 914 | checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" 915 | 916 | [[package]] 917 | name = "matchit" 918 | version = "0.4.4" 919 | source = "registry+https://github.com/rust-lang/crates.io-index" 920 | checksum = "58b6f41fdfbec185dd3dff58b51e323f5bc61692c0de38419a957b0dcfccca3c" 921 | 922 | [[package]] 923 | name = "md-5" 924 | version = "0.9.1" 925 | source = "registry+https://github.com/rust-lang/crates.io-index" 926 | checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15" 927 | dependencies = [ 928 | "block-buffer", 929 | "digest", 930 | "opaque-debug", 931 | ] 932 | 933 | [[package]] 934 | name = "memchr" 935 | version = "2.4.1" 936 | source = "registry+https://github.com/rust-lang/crates.io-index" 937 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 938 | 939 | [[package]] 940 | name = "memoffset" 941 | version = "0.6.5" 942 | source = "registry+https://github.com/rust-lang/crates.io-index" 943 | checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" 944 | dependencies = [ 945 | "autocfg", 946 | ] 947 | 948 | [[package]] 949 | name = "mime" 950 | version = "0.3.16" 951 | source = "registry+https://github.com/rust-lang/crates.io-index" 952 | checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" 953 | 954 | [[package]] 955 | name = "minimal-lexical" 956 | version = "0.2.1" 957 | source = "registry+https://github.com/rust-lang/crates.io-index" 958 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 959 | 960 | [[package]] 961 | name = "miniz_oxide" 962 | version = "0.4.4" 963 | source = "registry+https://github.com/rust-lang/crates.io-index" 964 | checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" 965 | dependencies = [ 966 | "adler", 967 | "autocfg", 968 | ] 969 | 970 | [[package]] 971 | name = "mio" 972 | version = "0.7.14" 973 | source = "registry+https://github.com/rust-lang/crates.io-index" 974 | checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" 975 | dependencies = [ 976 | "libc", 977 | "log", 978 | "miow", 979 | "ntapi", 980 | "winapi", 981 | ] 982 | 983 | [[package]] 984 | name = "miow" 985 | version = "0.3.7" 986 | source = "registry+https://github.com/rust-lang/crates.io-index" 987 | checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" 988 | dependencies = [ 989 | "winapi", 990 | ] 991 | 992 | [[package]] 993 | name = "mockall" 994 | version = "0.11.0" 995 | source = "registry+https://github.com/rust-lang/crates.io-index" 996 | checksum = "3d4d70639a72f972725db16350db56da68266ca368b2a1fe26724a903ad3d6b8" 997 | dependencies = [ 998 | "cfg-if", 999 | "downcast", 1000 | "fragile", 1001 | "lazy_static", 1002 | "mockall_derive", 1003 | "predicates", 1004 | "predicates-tree", 1005 | ] 1006 | 1007 | [[package]] 1008 | name = "mockall_derive" 1009 | version = "0.11.0" 1010 | source = "registry+https://github.com/rust-lang/crates.io-index" 1011 | checksum = "79ef208208a0dea3f72221e26e904cdc6db2e481d9ade89081ddd494f1dbaa6b" 1012 | dependencies = [ 1013 | "cfg-if", 1014 | "proc-macro2", 1015 | "quote", 1016 | "syn", 1017 | ] 1018 | 1019 | [[package]] 1020 | name = "multer" 1021 | version = "2.0.2" 1022 | source = "registry+https://github.com/rust-lang/crates.io-index" 1023 | checksum = "5f8f35e687561d5c1667590911e6698a8cb714a134a7505718a182e7bc9d3836" 1024 | dependencies = [ 1025 | "bytes", 1026 | "encoding_rs", 1027 | "futures-util", 1028 | "http", 1029 | "httparse", 1030 | "log", 1031 | "memchr", 1032 | "mime", 1033 | "spin", 1034 | "version_check", 1035 | ] 1036 | 1037 | [[package]] 1038 | name = "mutate_once" 1039 | version = "0.1.1" 1040 | source = "registry+https://github.com/rust-lang/crates.io-index" 1041 | checksum = "16cf681a23b4d0a43fc35024c176437f9dcd818db34e0f42ab456a0ee5ad497b" 1042 | 1043 | [[package]] 1044 | name = "nanorand" 1045 | version = "0.6.1" 1046 | source = "registry+https://github.com/rust-lang/crates.io-index" 1047 | checksum = "729eb334247daa1803e0a094d0a5c55711b85571179f5ec6e53eccfdf7008958" 1048 | dependencies = [ 1049 | "getrandom", 1050 | ] 1051 | 1052 | [[package]] 1053 | name = "native-tls" 1054 | version = "0.2.8" 1055 | source = "registry+https://github.com/rust-lang/crates.io-index" 1056 | checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" 1057 | dependencies = [ 1058 | "lazy_static", 1059 | "libc", 1060 | "log", 1061 | "openssl", 1062 | "openssl-probe", 1063 | "openssl-sys", 1064 | "schannel", 1065 | "security-framework", 1066 | "security-framework-sys", 1067 | "tempfile", 1068 | ] 1069 | 1070 | [[package]] 1071 | name = "nom" 1072 | version = "7.1.0" 1073 | source = "registry+https://github.com/rust-lang/crates.io-index" 1074 | checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" 1075 | dependencies = [ 1076 | "memchr", 1077 | "minimal-lexical", 1078 | "version_check", 1079 | ] 1080 | 1081 | [[package]] 1082 | name = "normalize-line-endings" 1083 | version = "0.3.0" 1084 | source = "registry+https://github.com/rust-lang/crates.io-index" 1085 | checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" 1086 | 1087 | [[package]] 1088 | name = "ntapi" 1089 | version = "0.3.6" 1090 | source = "registry+https://github.com/rust-lang/crates.io-index" 1091 | checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" 1092 | dependencies = [ 1093 | "winapi", 1094 | ] 1095 | 1096 | [[package]] 1097 | name = "num-integer" 1098 | version = "0.1.44" 1099 | source = "registry+https://github.com/rust-lang/crates.io-index" 1100 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 1101 | dependencies = [ 1102 | "autocfg", 1103 | "num-traits", 1104 | ] 1105 | 1106 | [[package]] 1107 | name = "num-iter" 1108 | version = "0.1.42" 1109 | source = "registry+https://github.com/rust-lang/crates.io-index" 1110 | checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" 1111 | dependencies = [ 1112 | "autocfg", 1113 | "num-integer", 1114 | "num-traits", 1115 | ] 1116 | 1117 | [[package]] 1118 | name = "num-rational" 1119 | version = "0.4.0" 1120 | source = "registry+https://github.com/rust-lang/crates.io-index" 1121 | checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a" 1122 | dependencies = [ 1123 | "autocfg", 1124 | "num-integer", 1125 | "num-traits", 1126 | ] 1127 | 1128 | [[package]] 1129 | name = "num-traits" 1130 | version = "0.2.14" 1131 | source = "registry+https://github.com/rust-lang/crates.io-index" 1132 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 1133 | dependencies = [ 1134 | "autocfg", 1135 | ] 1136 | 1137 | [[package]] 1138 | name = "num_cpus" 1139 | version = "1.13.1" 1140 | source = "registry+https://github.com/rust-lang/crates.io-index" 1141 | checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" 1142 | dependencies = [ 1143 | "hermit-abi", 1144 | "libc", 1145 | ] 1146 | 1147 | [[package]] 1148 | name = "once_cell" 1149 | version = "1.9.0" 1150 | source = "registry+https://github.com/rust-lang/crates.io-index" 1151 | checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" 1152 | 1153 | [[package]] 1154 | name = "opaque-debug" 1155 | version = "0.3.0" 1156 | source = "registry+https://github.com/rust-lang/crates.io-index" 1157 | checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" 1158 | 1159 | [[package]] 1160 | name = "openssl" 1161 | version = "0.10.38" 1162 | source = "registry+https://github.com/rust-lang/crates.io-index" 1163 | checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" 1164 | dependencies = [ 1165 | "bitflags", 1166 | "cfg-if", 1167 | "foreign-types", 1168 | "libc", 1169 | "once_cell", 1170 | "openssl-sys", 1171 | ] 1172 | 1173 | [[package]] 1174 | name = "openssl-probe" 1175 | version = "0.1.5" 1176 | source = "registry+https://github.com/rust-lang/crates.io-index" 1177 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 1178 | 1179 | [[package]] 1180 | name = "openssl-sys" 1181 | version = "0.9.72" 1182 | source = "registry+https://github.com/rust-lang/crates.io-index" 1183 | checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb" 1184 | dependencies = [ 1185 | "autocfg", 1186 | "cc", 1187 | "libc", 1188 | "pkg-config", 1189 | "vcpkg", 1190 | ] 1191 | 1192 | [[package]] 1193 | name = "parking_lot" 1194 | version = "0.11.2" 1195 | source = "registry+https://github.com/rust-lang/crates.io-index" 1196 | checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" 1197 | dependencies = [ 1198 | "instant", 1199 | "lock_api", 1200 | "parking_lot_core", 1201 | ] 1202 | 1203 | [[package]] 1204 | name = "parking_lot_core" 1205 | version = "0.8.5" 1206 | source = "registry+https://github.com/rust-lang/crates.io-index" 1207 | checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" 1208 | dependencies = [ 1209 | "cfg-if", 1210 | "instant", 1211 | "libc", 1212 | "redox_syscall", 1213 | "smallvec", 1214 | "winapi", 1215 | ] 1216 | 1217 | [[package]] 1218 | name = "percent-encoding" 1219 | version = "2.1.0" 1220 | source = "registry+https://github.com/rust-lang/crates.io-index" 1221 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 1222 | 1223 | [[package]] 1224 | name = "pin-project" 1225 | version = "1.0.10" 1226 | source = "registry+https://github.com/rust-lang/crates.io-index" 1227 | checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e" 1228 | dependencies = [ 1229 | "pin-project-internal", 1230 | ] 1231 | 1232 | [[package]] 1233 | name = "pin-project-internal" 1234 | version = "1.0.10" 1235 | source = "registry+https://github.com/rust-lang/crates.io-index" 1236 | checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb" 1237 | dependencies = [ 1238 | "proc-macro2", 1239 | "quote", 1240 | "syn", 1241 | ] 1242 | 1243 | [[package]] 1244 | name = "pin-project-lite" 1245 | version = "0.2.8" 1246 | source = "registry+https://github.com/rust-lang/crates.io-index" 1247 | checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" 1248 | 1249 | [[package]] 1250 | name = "pin-utils" 1251 | version = "0.1.0" 1252 | source = "registry+https://github.com/rust-lang/crates.io-index" 1253 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1254 | 1255 | [[package]] 1256 | name = "pkg-config" 1257 | version = "0.3.24" 1258 | source = "registry+https://github.com/rust-lang/crates.io-index" 1259 | checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" 1260 | 1261 | [[package]] 1262 | name = "png" 1263 | version = "0.17.2" 1264 | source = "registry+https://github.com/rust-lang/crates.io-index" 1265 | checksum = "c845088517daa61e8a57eee40309347cea13f273694d1385c553e7a57127763b" 1266 | dependencies = [ 1267 | "bitflags", 1268 | "crc32fast", 1269 | "deflate 0.9.1", 1270 | "encoding", 1271 | "miniz_oxide", 1272 | ] 1273 | 1274 | [[package]] 1275 | name = "ppv-lite86" 1276 | version = "0.2.16" 1277 | source = "registry+https://github.com/rust-lang/crates.io-index" 1278 | checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" 1279 | 1280 | [[package]] 1281 | name = "predicates" 1282 | version = "2.1.1" 1283 | source = "registry+https://github.com/rust-lang/crates.io-index" 1284 | checksum = "a5aab5be6e4732b473071984b3164dbbfb7a3674d30ea5ff44410b6bcd960c3c" 1285 | dependencies = [ 1286 | "difflib", 1287 | "float-cmp", 1288 | "itertools", 1289 | "normalize-line-endings", 1290 | "predicates-core", 1291 | "regex", 1292 | ] 1293 | 1294 | [[package]] 1295 | name = "predicates-core" 1296 | version = "1.0.3" 1297 | source = "registry+https://github.com/rust-lang/crates.io-index" 1298 | checksum = "da1c2388b1513e1b605fcec39a95e0a9e8ef088f71443ef37099fa9ae6673fcb" 1299 | 1300 | [[package]] 1301 | name = "predicates-tree" 1302 | version = "1.0.5" 1303 | source = "registry+https://github.com/rust-lang/crates.io-index" 1304 | checksum = "4d86de6de25020a36c6d3643a86d9a6a9f552107c0559c60ea03551b5e16c032" 1305 | dependencies = [ 1306 | "predicates-core", 1307 | "termtree", 1308 | ] 1309 | 1310 | [[package]] 1311 | name = "proc-macro2" 1312 | version = "1.0.36" 1313 | source = "registry+https://github.com/rust-lang/crates.io-index" 1314 | checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" 1315 | dependencies = [ 1316 | "unicode-xid", 1317 | ] 1318 | 1319 | [[package]] 1320 | name = "quote" 1321 | version = "1.0.15" 1322 | source = "registry+https://github.com/rust-lang/crates.io-index" 1323 | checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" 1324 | dependencies = [ 1325 | "proc-macro2", 1326 | ] 1327 | 1328 | [[package]] 1329 | name = "rand" 1330 | version = "0.8.4" 1331 | source = "registry+https://github.com/rust-lang/crates.io-index" 1332 | checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" 1333 | dependencies = [ 1334 | "libc", 1335 | "rand_chacha", 1336 | "rand_core", 1337 | "rand_hc", 1338 | ] 1339 | 1340 | [[package]] 1341 | name = "rand_chacha" 1342 | version = "0.3.1" 1343 | source = "registry+https://github.com/rust-lang/crates.io-index" 1344 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1345 | dependencies = [ 1346 | "ppv-lite86", 1347 | "rand_core", 1348 | ] 1349 | 1350 | [[package]] 1351 | name = "rand_core" 1352 | version = "0.6.3" 1353 | source = "registry+https://github.com/rust-lang/crates.io-index" 1354 | checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" 1355 | dependencies = [ 1356 | "getrandom", 1357 | ] 1358 | 1359 | [[package]] 1360 | name = "rand_hc" 1361 | version = "0.3.1" 1362 | source = "registry+https://github.com/rust-lang/crates.io-index" 1363 | checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" 1364 | dependencies = [ 1365 | "rand_core", 1366 | ] 1367 | 1368 | [[package]] 1369 | name = "rayon" 1370 | version = "1.5.1" 1371 | source = "registry+https://github.com/rust-lang/crates.io-index" 1372 | checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" 1373 | dependencies = [ 1374 | "autocfg", 1375 | "crossbeam-deque", 1376 | "either", 1377 | "rayon-core", 1378 | ] 1379 | 1380 | [[package]] 1381 | name = "rayon-core" 1382 | version = "1.9.1" 1383 | source = "registry+https://github.com/rust-lang/crates.io-index" 1384 | checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" 1385 | dependencies = [ 1386 | "crossbeam-channel", 1387 | "crossbeam-deque", 1388 | "crossbeam-utils", 1389 | "lazy_static", 1390 | "num_cpus", 1391 | ] 1392 | 1393 | [[package]] 1394 | name = "redox_syscall" 1395 | version = "0.2.10" 1396 | source = "registry+https://github.com/rust-lang/crates.io-index" 1397 | checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" 1398 | dependencies = [ 1399 | "bitflags", 1400 | ] 1401 | 1402 | [[package]] 1403 | name = "redox_users" 1404 | version = "0.4.0" 1405 | source = "registry+https://github.com/rust-lang/crates.io-index" 1406 | checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" 1407 | dependencies = [ 1408 | "getrandom", 1409 | "redox_syscall", 1410 | ] 1411 | 1412 | [[package]] 1413 | name = "regex" 1414 | version = "1.5.4" 1415 | source = "registry+https://github.com/rust-lang/crates.io-index" 1416 | checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" 1417 | dependencies = [ 1418 | "aho-corasick", 1419 | "memchr", 1420 | "regex-syntax", 1421 | ] 1422 | 1423 | [[package]] 1424 | name = "regex-automata" 1425 | version = "0.1.10" 1426 | source = "registry+https://github.com/rust-lang/crates.io-index" 1427 | checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" 1428 | dependencies = [ 1429 | "regex-syntax", 1430 | ] 1431 | 1432 | [[package]] 1433 | name = "regex-syntax" 1434 | version = "0.6.25" 1435 | source = "registry+https://github.com/rust-lang/crates.io-index" 1436 | checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" 1437 | 1438 | [[package]] 1439 | name = "remove_dir_all" 1440 | version = "0.5.3" 1441 | source = "registry+https://github.com/rust-lang/crates.io-index" 1442 | checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" 1443 | dependencies = [ 1444 | "winapi", 1445 | ] 1446 | 1447 | [[package]] 1448 | name = "rust-axum-sqlx-1" 1449 | version = "0.1.0" 1450 | dependencies = [ 1451 | "anyhow", 1452 | "async-trait", 1453 | "axum", 1454 | "dotenv", 1455 | "hyper", 1456 | "image", 1457 | "kamadak-exif", 1458 | "mockall", 1459 | "serde", 1460 | "serde_json", 1461 | "sqlx", 1462 | "thiserror", 1463 | "tokio", 1464 | "tower", 1465 | "tower-http", 1466 | "tracing", 1467 | "tracing-subscriber", 1468 | "uuid", 1469 | ] 1470 | 1471 | [[package]] 1472 | name = "ryu" 1473 | version = "1.0.9" 1474 | source = "registry+https://github.com/rust-lang/crates.io-index" 1475 | checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" 1476 | 1477 | [[package]] 1478 | name = "schannel" 1479 | version = "0.1.19" 1480 | source = "registry+https://github.com/rust-lang/crates.io-index" 1481 | checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" 1482 | dependencies = [ 1483 | "lazy_static", 1484 | "winapi", 1485 | ] 1486 | 1487 | [[package]] 1488 | name = "scoped_threadpool" 1489 | version = "0.1.9" 1490 | source = "registry+https://github.com/rust-lang/crates.io-index" 1491 | checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" 1492 | 1493 | [[package]] 1494 | name = "scopeguard" 1495 | version = "1.1.0" 1496 | source = "registry+https://github.com/rust-lang/crates.io-index" 1497 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1498 | 1499 | [[package]] 1500 | name = "security-framework" 1501 | version = "2.5.0" 1502 | source = "registry+https://github.com/rust-lang/crates.io-index" 1503 | checksum = "d09d3c15d814eda1d6a836f2f2b56a6abc1446c8a34351cb3180d3db92ffe4ce" 1504 | dependencies = [ 1505 | "bitflags", 1506 | "core-foundation", 1507 | "core-foundation-sys", 1508 | "libc", 1509 | "security-framework-sys", 1510 | ] 1511 | 1512 | [[package]] 1513 | name = "security-framework-sys" 1514 | version = "2.5.0" 1515 | source = "registry+https://github.com/rust-lang/crates.io-index" 1516 | checksum = "e90dd10c41c6bfc633da6e0c659bd25d31e0791e5974ac42970267d59eba87f7" 1517 | dependencies = [ 1518 | "core-foundation-sys", 1519 | "libc", 1520 | ] 1521 | 1522 | [[package]] 1523 | name = "serde" 1524 | version = "1.0.135" 1525 | source = "registry+https://github.com/rust-lang/crates.io-index" 1526 | checksum = "2cf9235533494ea2ddcdb794665461814781c53f19d87b76e571a1c35acbad2b" 1527 | dependencies = [ 1528 | "serde_derive", 1529 | ] 1530 | 1531 | [[package]] 1532 | name = "serde_derive" 1533 | version = "1.0.135" 1534 | source = "registry+https://github.com/rust-lang/crates.io-index" 1535 | checksum = "8dcde03d87d4c973c04be249e7d8f0b35db1c848c487bd43032808e59dd8328d" 1536 | dependencies = [ 1537 | "proc-macro2", 1538 | "quote", 1539 | "syn", 1540 | ] 1541 | 1542 | [[package]] 1543 | name = "serde_json" 1544 | version = "1.0.78" 1545 | source = "registry+https://github.com/rust-lang/crates.io-index" 1546 | checksum = "d23c1ba4cf0efd44be32017709280b32d1cea5c3f1275c3b6d9e8bc54f758085" 1547 | dependencies = [ 1548 | "itoa 1.0.1", 1549 | "ryu", 1550 | "serde", 1551 | ] 1552 | 1553 | [[package]] 1554 | name = "serde_urlencoded" 1555 | version = "0.7.1" 1556 | source = "registry+https://github.com/rust-lang/crates.io-index" 1557 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1558 | dependencies = [ 1559 | "form_urlencoded", 1560 | "itoa 1.0.1", 1561 | "ryu", 1562 | "serde", 1563 | ] 1564 | 1565 | [[package]] 1566 | name = "sha-1" 1567 | version = "0.9.8" 1568 | source = "registry+https://github.com/rust-lang/crates.io-index" 1569 | checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" 1570 | dependencies = [ 1571 | "block-buffer", 1572 | "cfg-if", 1573 | "cpufeatures", 1574 | "digest", 1575 | "opaque-debug", 1576 | ] 1577 | 1578 | [[package]] 1579 | name = "sha2" 1580 | version = "0.9.9" 1581 | source = "registry+https://github.com/rust-lang/crates.io-index" 1582 | checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" 1583 | dependencies = [ 1584 | "block-buffer", 1585 | "cfg-if", 1586 | "cpufeatures", 1587 | "digest", 1588 | "opaque-debug", 1589 | ] 1590 | 1591 | [[package]] 1592 | name = "sharded-slab" 1593 | version = "0.1.4" 1594 | source = "registry+https://github.com/rust-lang/crates.io-index" 1595 | checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" 1596 | dependencies = [ 1597 | "lazy_static", 1598 | ] 1599 | 1600 | [[package]] 1601 | name = "signal-hook-registry" 1602 | version = "1.4.0" 1603 | source = "registry+https://github.com/rust-lang/crates.io-index" 1604 | checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" 1605 | dependencies = [ 1606 | "libc", 1607 | ] 1608 | 1609 | [[package]] 1610 | name = "smallvec" 1611 | version = "1.8.0" 1612 | source = "registry+https://github.com/rust-lang/crates.io-index" 1613 | checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" 1614 | 1615 | [[package]] 1616 | name = "socket2" 1617 | version = "0.4.3" 1618 | source = "registry+https://github.com/rust-lang/crates.io-index" 1619 | checksum = "0f82496b90c36d70af5fcd482edaa2e0bd16fade569de1330405fecbbdac736b" 1620 | dependencies = [ 1621 | "libc", 1622 | "winapi", 1623 | ] 1624 | 1625 | [[package]] 1626 | name = "spin" 1627 | version = "0.9.2" 1628 | source = "registry+https://github.com/rust-lang/crates.io-index" 1629 | checksum = "511254be0c5bcf062b019a6c89c01a664aa359ded62f78aa72c6fc137c0590e5" 1630 | dependencies = [ 1631 | "lock_api", 1632 | ] 1633 | 1634 | [[package]] 1635 | name = "sqlformat" 1636 | version = "0.1.8" 1637 | source = "registry+https://github.com/rust-lang/crates.io-index" 1638 | checksum = "b4b7922be017ee70900be125523f38bdd644f4f06a1b16e8fa5a8ee8c34bffd4" 1639 | dependencies = [ 1640 | "itertools", 1641 | "nom", 1642 | "unicode_categories", 1643 | ] 1644 | 1645 | [[package]] 1646 | name = "sqlx" 1647 | version = "0.5.10" 1648 | source = "registry+https://github.com/rust-lang/crates.io-index" 1649 | checksum = "692749de69603d81e016212199d73a2e14ee20e2def7d7914919e8db5d4d48b9" 1650 | dependencies = [ 1651 | "sqlx-core", 1652 | "sqlx-macros", 1653 | ] 1654 | 1655 | [[package]] 1656 | name = "sqlx-core" 1657 | version = "0.5.10" 1658 | source = "registry+https://github.com/rust-lang/crates.io-index" 1659 | checksum = "518be6f6fff5ca76f985d434f9c37f3662af279642acf730388f271dff7b9016" 1660 | dependencies = [ 1661 | "ahash", 1662 | "atoi", 1663 | "base64", 1664 | "bitflags", 1665 | "byteorder", 1666 | "bytes", 1667 | "crc", 1668 | "crossbeam-channel", 1669 | "crossbeam-queue", 1670 | "crossbeam-utils", 1671 | "dirs", 1672 | "either", 1673 | "futures-channel", 1674 | "futures-core", 1675 | "futures-intrusive", 1676 | "futures-util", 1677 | "hashlink", 1678 | "hex", 1679 | "hmac", 1680 | "indexmap", 1681 | "itoa 1.0.1", 1682 | "libc", 1683 | "log", 1684 | "md-5", 1685 | "memchr", 1686 | "once_cell", 1687 | "parking_lot", 1688 | "percent-encoding", 1689 | "rand", 1690 | "serde", 1691 | "serde_json", 1692 | "sha-1", 1693 | "sha2", 1694 | "smallvec", 1695 | "sqlformat", 1696 | "sqlx-rt", 1697 | "stringprep", 1698 | "thiserror", 1699 | "tokio-stream", 1700 | "url", 1701 | "whoami", 1702 | ] 1703 | 1704 | [[package]] 1705 | name = "sqlx-macros" 1706 | version = "0.5.10" 1707 | source = "registry+https://github.com/rust-lang/crates.io-index" 1708 | checksum = "38e45140529cf1f90a5e1c2e561500ca345821a1c513652c8f486bbf07407cc8" 1709 | dependencies = [ 1710 | "dotenv", 1711 | "either", 1712 | "heck", 1713 | "once_cell", 1714 | "proc-macro2", 1715 | "quote", 1716 | "sha2", 1717 | "sqlx-core", 1718 | "sqlx-rt", 1719 | "syn", 1720 | "url", 1721 | ] 1722 | 1723 | [[package]] 1724 | name = "sqlx-rt" 1725 | version = "0.5.10" 1726 | source = "registry+https://github.com/rust-lang/crates.io-index" 1727 | checksum = "8061cbaa91ee75041514f67a09398c65a64efed72c90151ecd47593bad53da99" 1728 | dependencies = [ 1729 | "native-tls", 1730 | "once_cell", 1731 | "tokio", 1732 | "tokio-native-tls", 1733 | ] 1734 | 1735 | [[package]] 1736 | name = "stringprep" 1737 | version = "0.1.2" 1738 | source = "registry+https://github.com/rust-lang/crates.io-index" 1739 | checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" 1740 | dependencies = [ 1741 | "unicode-bidi", 1742 | "unicode-normalization", 1743 | ] 1744 | 1745 | [[package]] 1746 | name = "subtle" 1747 | version = "2.4.1" 1748 | source = "registry+https://github.com/rust-lang/crates.io-index" 1749 | checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" 1750 | 1751 | [[package]] 1752 | name = "syn" 1753 | version = "1.0.86" 1754 | source = "registry+https://github.com/rust-lang/crates.io-index" 1755 | checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" 1756 | dependencies = [ 1757 | "proc-macro2", 1758 | "quote", 1759 | "unicode-xid", 1760 | ] 1761 | 1762 | [[package]] 1763 | name = "sync_wrapper" 1764 | version = "0.1.1" 1765 | source = "registry+https://github.com/rust-lang/crates.io-index" 1766 | checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" 1767 | 1768 | [[package]] 1769 | name = "tempfile" 1770 | version = "3.3.0" 1771 | source = "registry+https://github.com/rust-lang/crates.io-index" 1772 | checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" 1773 | dependencies = [ 1774 | "cfg-if", 1775 | "fastrand", 1776 | "libc", 1777 | "redox_syscall", 1778 | "remove_dir_all", 1779 | "winapi", 1780 | ] 1781 | 1782 | [[package]] 1783 | name = "termtree" 1784 | version = "0.2.4" 1785 | source = "registry+https://github.com/rust-lang/crates.io-index" 1786 | checksum = "507e9898683b6c43a9aa55b64259b721b52ba226e0f3779137e50ad114a4c90b" 1787 | 1788 | [[package]] 1789 | name = "thiserror" 1790 | version = "1.0.30" 1791 | source = "registry+https://github.com/rust-lang/crates.io-index" 1792 | checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" 1793 | dependencies = [ 1794 | "thiserror-impl", 1795 | ] 1796 | 1797 | [[package]] 1798 | name = "thiserror-impl" 1799 | version = "1.0.30" 1800 | source = "registry+https://github.com/rust-lang/crates.io-index" 1801 | checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" 1802 | dependencies = [ 1803 | "proc-macro2", 1804 | "quote", 1805 | "syn", 1806 | ] 1807 | 1808 | [[package]] 1809 | name = "thread_local" 1810 | version = "1.1.4" 1811 | source = "registry+https://github.com/rust-lang/crates.io-index" 1812 | checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" 1813 | dependencies = [ 1814 | "once_cell", 1815 | ] 1816 | 1817 | [[package]] 1818 | name = "threadpool" 1819 | version = "1.8.1" 1820 | source = "registry+https://github.com/rust-lang/crates.io-index" 1821 | checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" 1822 | dependencies = [ 1823 | "num_cpus", 1824 | ] 1825 | 1826 | [[package]] 1827 | name = "tiff" 1828 | version = "0.7.1" 1829 | source = "registry+https://github.com/rust-lang/crates.io-index" 1830 | checksum = "0247608e998cb6ce39dfc8f4a16c50361ce71e5b52e6d24ea1227ea8ea8ee0b2" 1831 | dependencies = [ 1832 | "flate2", 1833 | "jpeg-decoder 0.1.22", 1834 | "weezl", 1835 | ] 1836 | 1837 | [[package]] 1838 | name = "tinyvec" 1839 | version = "1.5.1" 1840 | source = "registry+https://github.com/rust-lang/crates.io-index" 1841 | checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" 1842 | dependencies = [ 1843 | "tinyvec_macros", 1844 | ] 1845 | 1846 | [[package]] 1847 | name = "tinyvec_macros" 1848 | version = "0.1.0" 1849 | source = "registry+https://github.com/rust-lang/crates.io-index" 1850 | checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" 1851 | 1852 | [[package]] 1853 | name = "tokio" 1854 | version = "1.15.0" 1855 | source = "registry+https://github.com/rust-lang/crates.io-index" 1856 | checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838" 1857 | dependencies = [ 1858 | "bytes", 1859 | "libc", 1860 | "memchr", 1861 | "mio", 1862 | "num_cpus", 1863 | "once_cell", 1864 | "parking_lot", 1865 | "pin-project-lite", 1866 | "signal-hook-registry", 1867 | "tokio-macros", 1868 | "winapi", 1869 | ] 1870 | 1871 | [[package]] 1872 | name = "tokio-macros" 1873 | version = "1.7.0" 1874 | source = "registry+https://github.com/rust-lang/crates.io-index" 1875 | checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" 1876 | dependencies = [ 1877 | "proc-macro2", 1878 | "quote", 1879 | "syn", 1880 | ] 1881 | 1882 | [[package]] 1883 | name = "tokio-native-tls" 1884 | version = "0.3.0" 1885 | source = "registry+https://github.com/rust-lang/crates.io-index" 1886 | checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" 1887 | dependencies = [ 1888 | "native-tls", 1889 | "tokio", 1890 | ] 1891 | 1892 | [[package]] 1893 | name = "tokio-stream" 1894 | version = "0.1.8" 1895 | source = "registry+https://github.com/rust-lang/crates.io-index" 1896 | checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" 1897 | dependencies = [ 1898 | "futures-core", 1899 | "pin-project-lite", 1900 | "tokio", 1901 | ] 1902 | 1903 | [[package]] 1904 | name = "tokio-util" 1905 | version = "0.6.9" 1906 | source = "registry+https://github.com/rust-lang/crates.io-index" 1907 | checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" 1908 | dependencies = [ 1909 | "bytes", 1910 | "futures-core", 1911 | "futures-sink", 1912 | "log", 1913 | "pin-project-lite", 1914 | "tokio", 1915 | ] 1916 | 1917 | [[package]] 1918 | name = "tower" 1919 | version = "0.4.11" 1920 | source = "registry+https://github.com/rust-lang/crates.io-index" 1921 | checksum = "5651b5f6860a99bd1adb59dbfe1db8beb433e73709d9032b413a77e2fb7c066a" 1922 | dependencies = [ 1923 | "futures-core", 1924 | "futures-util", 1925 | "pin-project", 1926 | "pin-project-lite", 1927 | "tokio", 1928 | "tokio-util", 1929 | "tower-layer", 1930 | "tower-service", 1931 | "tracing", 1932 | ] 1933 | 1934 | [[package]] 1935 | name = "tower-http" 1936 | version = "0.2.1" 1937 | source = "registry+https://github.com/rust-lang/crates.io-index" 1938 | checksum = "03650267ad175b51c47d02ed9547fc7d4ba2c7e5cb76df0bed67edd1825ae297" 1939 | dependencies = [ 1940 | "bitflags", 1941 | "bytes", 1942 | "futures-core", 1943 | "futures-util", 1944 | "http", 1945 | "http-body", 1946 | "http-range-header", 1947 | "pin-project-lite", 1948 | "tower-layer", 1949 | "tower-service", 1950 | ] 1951 | 1952 | [[package]] 1953 | name = "tower-layer" 1954 | version = "0.3.1" 1955 | source = "registry+https://github.com/rust-lang/crates.io-index" 1956 | checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" 1957 | 1958 | [[package]] 1959 | name = "tower-service" 1960 | version = "0.3.1" 1961 | source = "registry+https://github.com/rust-lang/crates.io-index" 1962 | checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" 1963 | 1964 | [[package]] 1965 | name = "tracing" 1966 | version = "0.1.29" 1967 | source = "registry+https://github.com/rust-lang/crates.io-index" 1968 | checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" 1969 | dependencies = [ 1970 | "cfg-if", 1971 | "log", 1972 | "pin-project-lite", 1973 | "tracing-attributes", 1974 | "tracing-core", 1975 | ] 1976 | 1977 | [[package]] 1978 | name = "tracing-attributes" 1979 | version = "0.1.18" 1980 | source = "registry+https://github.com/rust-lang/crates.io-index" 1981 | checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e" 1982 | dependencies = [ 1983 | "proc-macro2", 1984 | "quote", 1985 | "syn", 1986 | ] 1987 | 1988 | [[package]] 1989 | name = "tracing-core" 1990 | version = "0.1.21" 1991 | source = "registry+https://github.com/rust-lang/crates.io-index" 1992 | checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" 1993 | dependencies = [ 1994 | "lazy_static", 1995 | ] 1996 | 1997 | [[package]] 1998 | name = "tracing-log" 1999 | version = "0.1.2" 2000 | source = "registry+https://github.com/rust-lang/crates.io-index" 2001 | checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3" 2002 | dependencies = [ 2003 | "lazy_static", 2004 | "log", 2005 | "tracing-core", 2006 | ] 2007 | 2008 | [[package]] 2009 | name = "tracing-subscriber" 2010 | version = "0.3.6" 2011 | source = "registry+https://github.com/rust-lang/crates.io-index" 2012 | checksum = "77be66445c4eeebb934a7340f227bfe7b338173d3f8c00a60a5a58005c9faecf" 2013 | dependencies = [ 2014 | "ansi_term", 2015 | "lazy_static", 2016 | "matchers", 2017 | "regex", 2018 | "sharded-slab", 2019 | "smallvec", 2020 | "thread_local", 2021 | "tracing", 2022 | "tracing-core", 2023 | "tracing-log", 2024 | ] 2025 | 2026 | [[package]] 2027 | name = "try-lock" 2028 | version = "0.2.3" 2029 | source = "registry+https://github.com/rust-lang/crates.io-index" 2030 | checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" 2031 | 2032 | [[package]] 2033 | name = "typenum" 2034 | version = "1.15.0" 2035 | source = "registry+https://github.com/rust-lang/crates.io-index" 2036 | checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" 2037 | 2038 | [[package]] 2039 | name = "unicode-bidi" 2040 | version = "0.3.7" 2041 | source = "registry+https://github.com/rust-lang/crates.io-index" 2042 | checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" 2043 | 2044 | [[package]] 2045 | name = "unicode-normalization" 2046 | version = "0.1.19" 2047 | source = "registry+https://github.com/rust-lang/crates.io-index" 2048 | checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" 2049 | dependencies = [ 2050 | "tinyvec", 2051 | ] 2052 | 2053 | [[package]] 2054 | name = "unicode-segmentation" 2055 | version = "1.8.0" 2056 | source = "registry+https://github.com/rust-lang/crates.io-index" 2057 | checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" 2058 | 2059 | [[package]] 2060 | name = "unicode-xid" 2061 | version = "0.2.2" 2062 | source = "registry+https://github.com/rust-lang/crates.io-index" 2063 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 2064 | 2065 | [[package]] 2066 | name = "unicode_categories" 2067 | version = "0.1.1" 2068 | source = "registry+https://github.com/rust-lang/crates.io-index" 2069 | checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" 2070 | 2071 | [[package]] 2072 | name = "url" 2073 | version = "2.2.2" 2074 | source = "registry+https://github.com/rust-lang/crates.io-index" 2075 | checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" 2076 | dependencies = [ 2077 | "form_urlencoded", 2078 | "idna", 2079 | "matches", 2080 | "percent-encoding", 2081 | ] 2082 | 2083 | [[package]] 2084 | name = "uuid" 2085 | version = "0.8.2" 2086 | source = "registry+https://github.com/rust-lang/crates.io-index" 2087 | checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" 2088 | dependencies = [ 2089 | "getrandom", 2090 | "serde", 2091 | ] 2092 | 2093 | [[package]] 2094 | name = "vcpkg" 2095 | version = "0.2.15" 2096 | source = "registry+https://github.com/rust-lang/crates.io-index" 2097 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 2098 | 2099 | [[package]] 2100 | name = "version_check" 2101 | version = "0.9.4" 2102 | source = "registry+https://github.com/rust-lang/crates.io-index" 2103 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 2104 | 2105 | [[package]] 2106 | name = "want" 2107 | version = "0.3.0" 2108 | source = "registry+https://github.com/rust-lang/crates.io-index" 2109 | checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" 2110 | dependencies = [ 2111 | "log", 2112 | "try-lock", 2113 | ] 2114 | 2115 | [[package]] 2116 | name = "wasi" 2117 | version = "0.10.2+wasi-snapshot-preview1" 2118 | source = "registry+https://github.com/rust-lang/crates.io-index" 2119 | checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" 2120 | 2121 | [[package]] 2122 | name = "wasm-bindgen" 2123 | version = "0.2.79" 2124 | source = "registry+https://github.com/rust-lang/crates.io-index" 2125 | checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" 2126 | dependencies = [ 2127 | "cfg-if", 2128 | "wasm-bindgen-macro", 2129 | ] 2130 | 2131 | [[package]] 2132 | name = "wasm-bindgen-backend" 2133 | version = "0.2.79" 2134 | source = "registry+https://github.com/rust-lang/crates.io-index" 2135 | checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" 2136 | dependencies = [ 2137 | "bumpalo", 2138 | "lazy_static", 2139 | "log", 2140 | "proc-macro2", 2141 | "quote", 2142 | "syn", 2143 | "wasm-bindgen-shared", 2144 | ] 2145 | 2146 | [[package]] 2147 | name = "wasm-bindgen-macro" 2148 | version = "0.2.79" 2149 | source = "registry+https://github.com/rust-lang/crates.io-index" 2150 | checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" 2151 | dependencies = [ 2152 | "quote", 2153 | "wasm-bindgen-macro-support", 2154 | ] 2155 | 2156 | [[package]] 2157 | name = "wasm-bindgen-macro-support" 2158 | version = "0.2.79" 2159 | source = "registry+https://github.com/rust-lang/crates.io-index" 2160 | checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" 2161 | dependencies = [ 2162 | "proc-macro2", 2163 | "quote", 2164 | "syn", 2165 | "wasm-bindgen-backend", 2166 | "wasm-bindgen-shared", 2167 | ] 2168 | 2169 | [[package]] 2170 | name = "wasm-bindgen-shared" 2171 | version = "0.2.79" 2172 | source = "registry+https://github.com/rust-lang/crates.io-index" 2173 | checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" 2174 | 2175 | [[package]] 2176 | name = "web-sys" 2177 | version = "0.3.56" 2178 | source = "registry+https://github.com/rust-lang/crates.io-index" 2179 | checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" 2180 | dependencies = [ 2181 | "js-sys", 2182 | "wasm-bindgen", 2183 | ] 2184 | 2185 | [[package]] 2186 | name = "weezl" 2187 | version = "0.1.5" 2188 | source = "registry+https://github.com/rust-lang/crates.io-index" 2189 | checksum = "d8b77fdfd5a253be4ab714e4ffa3c49caf146b4de743e97510c0656cf90f1e8e" 2190 | 2191 | [[package]] 2192 | name = "whoami" 2193 | version = "1.2.1" 2194 | source = "registry+https://github.com/rust-lang/crates.io-index" 2195 | checksum = "524b58fa5a20a2fb3014dd6358b70e6579692a56ef6fce928834e488f42f65e8" 2196 | dependencies = [ 2197 | "wasm-bindgen", 2198 | "web-sys", 2199 | ] 2200 | 2201 | [[package]] 2202 | name = "winapi" 2203 | version = "0.3.9" 2204 | source = "registry+https://github.com/rust-lang/crates.io-index" 2205 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 2206 | dependencies = [ 2207 | "winapi-i686-pc-windows-gnu", 2208 | "winapi-x86_64-pc-windows-gnu", 2209 | ] 2210 | 2211 | [[package]] 2212 | name = "winapi-i686-pc-windows-gnu" 2213 | version = "0.4.0" 2214 | source = "registry+https://github.com/rust-lang/crates.io-index" 2215 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2216 | 2217 | [[package]] 2218 | name = "winapi-x86_64-pc-windows-gnu" 2219 | version = "0.4.0" 2220 | source = "registry+https://github.com/rust-lang/crates.io-index" 2221 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2222 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rust-axum-sqlx-1" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | axum = { version = "0.4", features = ["multipart"] } 10 | serde = { version = "1.0", features = ["derive"] } 11 | serde_json = "1.0" 12 | tokio = { version = "1.0", features = ["full"] } 13 | tracing = "0.1" 14 | tracing-subscriber = { version="0.3", features = ["env-filter"] } 15 | tower-http = { version = "0.2", features = ["cors"] } 16 | anyhow = "1.0" 17 | thiserror = "1.0" 18 | sqlx = { version = "0.5", features = [ "runtime-tokio-native-tls", "postgres" ]} 19 | dotenv = "0.15" 20 | mockall = "0.11" 21 | async-trait = "0.1" 22 | tower = { version = "0.4", features = ["util"] } 23 | image = "0.24" 24 | kamadak-exif = "0.5.4" 25 | uuid = { version = "0.8.2", features = ["serde", "v4"] } 26 | 27 | [dev-dependencies] 28 | hyper = "0.14" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 edo1z 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rust-axum-sqlx-sample 2 | 3 | ## Install 4 | 5 | ```shell 6 | git clone https://github.com/web3ten0/rust-axum-sqlx-1.git 7 | cd rust-axum-sqlx-1/local 8 | docker-compose up -d 9 | sh scripts/exec_init_db 10 | ``` 11 | 12 | ## Migration 13 | 14 | - 参照: https://github.com/launchbadge/sqlx/tree/master/sqlx-cli 15 | 16 | ```shell 17 | cd local/scripts 18 | sh migrate add -r users 19 | sh migrate run 20 | sh migrate revert 21 | ``` 22 | 23 | ## Swagger 24 | ### swagger-uiのURL 25 | - http://localhost:8001 26 | 27 | -------------------------------------------------------------------------------- /local/api/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:1.58.0 2 | WORKDIR /app 3 | RUN cargo install sqlx-cli && cargo install cargo-watch -------------------------------------------------------------------------------- /local/db/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM postgres:14.1-alpine 2 | ENV LANG ja-JP.utf8 -------------------------------------------------------------------------------- /local/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | services: 3 | db: 4 | build: ./db 5 | restart: always 6 | environment: 7 | POSTGRES_DB: 'database' 8 | POSTGRES_USER: 'user' 9 | POSTGRES_PASSWORD: 'password' 10 | ports: 11 | - "5433:5432" 12 | volumes: 13 | - db_data:/var/lib/postgresql/data 14 | api: 15 | build: ./api 16 | ports: 17 | - '8085:8080' 18 | depends_on: 19 | - db 20 | volumes: 21 | - ..:/app 22 | - cargo-cache:/app/target 23 | command: /bin/sh -c "cargo watch -x run" 24 | mailhog: 25 | image: mailhog/mailhog 26 | ports: 27 | - "8026:8025" 28 | - "1026:1025" 29 | swagger-ui: 30 | image: swaggerapi/swagger-ui 31 | ports: 32 | - 8001:8080 33 | volumes: 34 | - ../openapi:/openapi 35 | environment: 36 | SWAGGER_JSON: /openapi/openapi.yaml 37 | volumes: 38 | db_data: 39 | cargo-cache: 40 | target-cache: 41 | -------------------------------------------------------------------------------- /local/scripts/clear_permission: -------------------------------------------------------------------------------- 1 | docker exec local_api_1 chown -R 1000:1001 /app -------------------------------------------------------------------------------- /local/scripts/exec_init_db: -------------------------------------------------------------------------------- 1 | docker exec local_api_1 sh /app/local/scripts/init_db -------------------------------------------------------------------------------- /local/scripts/init_db: -------------------------------------------------------------------------------- 1 | cd /app 2 | echo "start database setup" 3 | sqlx migrate run 4 | chown -R 1000:1001 /app -------------------------------------------------------------------------------- /local/scripts/migrate: -------------------------------------------------------------------------------- 1 | docker exec local_api_1 sqlx migrate $1 $2 $3 2 | docker exec local_api_1 chown -R 1000:1001 /app -------------------------------------------------------------------------------- /migrations/20220121053505_users.down.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE users -------------------------------------------------------------------------------- /migrations/20220121053505_users.up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users ( 2 | id SERIAL PRIMARY KEY, 3 | name VARCHAR(30) NOT NULL, 4 | msg VARCHAR(140), 5 | age SMALLINT 6 | ) -------------------------------------------------------------------------------- /migrations/20220121060109_categories.down.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE categories -------------------------------------------------------------------------------- /migrations/20220121060109_categories.up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE categories ( 2 | id SERIAL PRIMARY KEY, 3 | name VARCHAR(50) NOT NULL 4 | ) -------------------------------------------------------------------------------- /migrations/20220121060224_posts.down.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE posts -------------------------------------------------------------------------------- /migrations/20220121060224_posts.up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE posts ( 2 | id SERIAL PRIMARY KEY, 3 | user_id INTEGER REFERENCES users (id), 4 | category_id INTEGER REFERENCES categories (id), 5 | title VARCHAR(140) NOT NULL, 6 | content TEXT 7 | ) 8 | -------------------------------------------------------------------------------- /openapi/openapi.yaml: -------------------------------------------------------------------------------- 1 | openapi: "3.0.1" 2 | info: 3 | title: "Rust Axum+SQLx Sample" 4 | description: "" 5 | version: 0.0.1 6 | servers: 7 | - url: http://localhost:8085 8 | tags: 9 | - name: user 10 | - name: category 11 | - name: post 12 | paths: 13 | "/users": 14 | $ref: "./paths/users/index.yaml" 15 | "/users/view/{userId}": 16 | $ref: "./paths/users/view.yaml" 17 | "/users/add": 18 | $ref: "./paths/users/add.yaml" 19 | "/users/edit/img/prof": 20 | $ref: "./paths/users/edit/img/profile.yaml" 21 | "/categories": 22 | $ref: "./paths/categories/index.yaml" 23 | "/categories/add": 24 | $ref: "./paths/categories/add.yaml" 25 | "/posts": 26 | $ref: "./paths/posts/index.yaml" 27 | "/posts/add": 28 | $ref: "./paths/posts/add.yaml" 29 | components: 30 | schemas: 31 | $ref: "./schemas/index.yaml" 32 | -------------------------------------------------------------------------------- /openapi/paths/categories/add.yaml: -------------------------------------------------------------------------------- 1 | post: 2 | tags: 3 | - "category" 4 | summary: add category 5 | operationId: add_category 6 | requestBody: 7 | description: "category info" 8 | content: 9 | application/json: 10 | schema: 11 | $ref: "../../schemas/category.yaml#/CreateCategory" 12 | responses: 13 | '200': 14 | description: return categoryId 15 | content: 16 | application/json: 17 | schema: 18 | $ref: "../../schemas/category.yaml#/CategoryId" -------------------------------------------------------------------------------- /openapi/paths/categories/index.yaml: -------------------------------------------------------------------------------- 1 | get: 2 | tags: 3 | - "category" 4 | summary: get 10 categories 5 | operationId: get_categores 6 | parameters: 7 | - name: "name" 8 | in: "query" 9 | description: "category name" 10 | required: false 11 | type: "string" 12 | responses: 13 | '200': 14 | description: return categories 15 | content: 16 | application/json: 17 | schema: 18 | type: "array" 19 | items: 20 | $ref: "../../schemas/category.yaml#/Category" -------------------------------------------------------------------------------- /openapi/paths/posts/add.yaml: -------------------------------------------------------------------------------- 1 | post: 2 | tags: 3 | - "post" 4 | summary: add post 5 | operationId: add_post 6 | requestBody: 7 | description: "post info" 8 | content: 9 | application/json: 10 | schema: 11 | $ref: "../../schemas/post.yaml#/CreatePost" 12 | responses: 13 | '200': 14 | description: return postId 15 | content: 16 | application/json: 17 | schema: 18 | $ref: "../../schemas/post.yaml#/PostId" 19 | -------------------------------------------------------------------------------- /openapi/paths/posts/index.yaml: -------------------------------------------------------------------------------- 1 | get: 2 | tags: 3 | - "post" 4 | summary: get 10 posts 5 | operationId: get_posts 6 | parameters: 7 | - name: "title" 8 | in: "query" 9 | description: "post title" 10 | required: false 11 | type: "string" 12 | responses: 13 | '200': 14 | description: return posts 15 | content: 16 | application/json: 17 | schema: 18 | type: "array" 19 | items: 20 | $ref: "../../schemas/post.yaml#/Post" -------------------------------------------------------------------------------- /openapi/paths/users/add.yaml: -------------------------------------------------------------------------------- 1 | post: 2 | tags: 3 | - "user" 4 | summary: add user 5 | operationId: add_user 6 | requestBody: 7 | description: "user info" 8 | content: 9 | application/json: 10 | schema: 11 | $ref: "../../schemas/user.yaml#/NewUser" 12 | responses: 13 | '200': 14 | description: return userId 15 | content: 16 | application/json: 17 | schema: 18 | $ref: "../../schemas/user.yaml#/UserId" -------------------------------------------------------------------------------- /openapi/paths/users/edit/img/profile.yaml: -------------------------------------------------------------------------------- 1 | post: 2 | tags: 3 | - "user" 4 | summary: upload profile image 5 | operationId: edit_user_image_profile 6 | requestBody: 7 | content: 8 | multipart/form-data: 9 | schema: 10 | $ref: "../../../../schemas/user.yaml#/ProfImg" 11 | responses: 12 | '200': 13 | description: return userId 14 | content: 15 | application/json: 16 | schema: 17 | $ref: "../../../../schemas/user.yaml#/ImgUrl" -------------------------------------------------------------------------------- /openapi/paths/users/index.yaml: -------------------------------------------------------------------------------- 1 | get: 2 | tags: 3 | - "user" 4 | summary: get 10 users 5 | operationId: get_users 6 | parameters: 7 | - name: "name" 8 | in: "query" 9 | description: "user name" 10 | required: false 11 | type: "string" 12 | responses: 13 | "200": 14 | description: return users 15 | content: 16 | application/json: 17 | schema: 18 | type: "array" 19 | items: 20 | $ref: "../../schemas/user.yaml#/User" 21 | -------------------------------------------------------------------------------- /openapi/paths/users/view.yaml: -------------------------------------------------------------------------------- 1 | get: 2 | tags: 3 | - "user" 4 | summary: view user 5 | operationId: view_users 6 | parameters: 7 | - name: "userId" 8 | in: "path" 9 | description: "user id" 10 | required: true 11 | type: "integer" 12 | responses: 13 | '200': 14 | description: return users 15 | content: 16 | application/json: 17 | schema: 18 | $ref: "../../schemas/user.yaml#/User" -------------------------------------------------------------------------------- /openapi/schemas/category.yaml: -------------------------------------------------------------------------------- 1 | Category: 2 | type: "object" 3 | properties: 4 | id: 5 | type: "integer" 6 | format: "int32" 7 | name: 8 | type: "string" 9 | 10 | CreateCategory: 11 | required: 12 | - name 13 | type: "object" 14 | properties: 15 | name: 16 | type: "string" 17 | 18 | CategoryId: 19 | type: "object" 20 | properties: 21 | id: 22 | type: "integer" 23 | format: "int32" -------------------------------------------------------------------------------- /openapi/schemas/index.yaml: -------------------------------------------------------------------------------- 1 | user: 2 | $ref: "./user.yaml" 3 | category: 4 | $ref: "./category.yaml" 5 | post: 6 | $ref: "./post.yaml" -------------------------------------------------------------------------------- /openapi/schemas/post.yaml: -------------------------------------------------------------------------------- 1 | Post: 2 | type: "object" 3 | properties: 4 | id: 5 | type: "integer" 6 | format: "int32" 7 | user_id: 8 | type: "integer" 9 | format: "int32" 10 | category_id: 11 | type: "integer" 12 | format: "int32" 13 | title: 14 | type: "string" 15 | content: 16 | type: "string" 17 | 18 | CreatePost: 19 | required: 20 | - user_id 21 | - category_id 22 | - title 23 | type: "object" 24 | properties: 25 | user_id: 26 | type: "integer" 27 | format: "int32" 28 | category_id: 29 | type: "integer" 30 | format: "int32" 31 | title: 32 | type: "string" 33 | content: 34 | type: "string" 35 | 36 | PostId: 37 | type: "object" 38 | properties: 39 | id: 40 | type: "integer" 41 | format: "int32" -------------------------------------------------------------------------------- /openapi/schemas/user.yaml: -------------------------------------------------------------------------------- 1 | User: 2 | type: "object" 3 | properties: 4 | id: 5 | required: true 6 | type: "integer" 7 | format: "int32" 8 | name: 9 | required: true 10 | type: "string" 11 | msg: 12 | required: false 13 | type: "string" 14 | age: 15 | required: false 16 | type: "integer" 17 | format: "int16" 18 | 19 | NewUser: 20 | required: 21 | - name 22 | type: "object" 23 | properties: 24 | name: 25 | type: "string" 26 | msg: 27 | type: "string" 28 | age: 29 | type: "integer" 30 | format: "int16" 31 | 32 | UserId: 33 | type: "object" 34 | properties: 35 | id: 36 | type: "integer" 37 | format: "int32" 38 | 39 | ProfImg: 40 | type: object 41 | properties: 42 | user_id: 43 | required: true 44 | type: integer 45 | format: int32 46 | prof_img: 47 | required: true 48 | type: string 49 | format: binary 50 | 51 | ImgUrl: 52 | type: object 53 | properties: 54 | url: 55 | type: string -------------------------------------------------------------------------------- /src/bootstrap/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::repositories::create_repositories; 2 | use crate::router::router; 3 | use axum::{http::header::CONTENT_TYPE, AddExtensionLayer, Router}; 4 | use std::sync::Arc; 5 | use tower_http::cors::{any, CorsLayer, Origin}; 6 | 7 | pub fn cors() -> CorsLayer { 8 | let swagger_url = "http://localhost:8001"; 9 | CorsLayer::new() 10 | .allow_origin(Origin::exact(swagger_url.parse().unwrap())) 11 | .allow_methods(any()) 12 | .allow_headers(vec![CONTENT_TYPE]) 13 | } 14 | 15 | pub async fn create_app() -> Router { 16 | let repositories = Arc::new(create_repositories().await); 17 | router() 18 | .layer(cors()) 19 | .layer(AddExtensionLayer::new(repositories)) 20 | } 21 | -------------------------------------------------------------------------------- /src/controllers/categories.rs: -------------------------------------------------------------------------------- 1 | use crate::error::Result; 2 | use crate::models::category::{ 3 | Category, CategoryConditions, CategoryId, CategoryList, CreateCategory, 4 | }; 5 | use crate::repositories::{category::CategoryRepo, RepoExt, Repositories}; 6 | use axum::{ 7 | extract::{Extension, Path, Query}, 8 | http::StatusCode, 9 | Json, 10 | }; 11 | 12 | pub async fn index( 13 | Query(conditions): Query, 14 | Extension(repo): RepoExt, 15 | ) -> Result> { 16 | let categories = repo.category().find_all(&conditions).await?; 17 | Ok(Json(categories)) 18 | } 19 | 20 | pub async fn view( 21 | Path(category_id): Path, 22 | Extension(repo): RepoExt, 23 | ) -> Result> { 24 | let category = repo.category().find_by_id(category_id).await?; 25 | Ok(Json(category)) 26 | } 27 | 28 | pub async fn add( 29 | Json(category_data): Json, 30 | Extension(repo): RepoExt, 31 | ) -> Result> { 32 | let category_id = repo.category().add(&category_data).await?; 33 | Ok(Json(category_id)) 34 | } 35 | 36 | pub async fn edit() -> StatusCode { 37 | StatusCode::OK 38 | } 39 | 40 | pub async fn delete() -> StatusCode { 41 | StatusCode::OK 42 | } 43 | -------------------------------------------------------------------------------- /src/controllers/middleware/mod.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edo1z/rust-axum-sqlx-sample/403a04e65fe48e55991bfaecaa5a6a9f67feed5a/src/controllers/middleware/mod.rs -------------------------------------------------------------------------------- /src/controllers/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod categories; 2 | pub mod posts; 3 | pub mod users; 4 | 5 | pub async fn root() -> &'static str { 6 | "hello" 7 | } 8 | 9 | #[cfg(test)] 10 | mod tests { 11 | use crate::router; 12 | use crate::tests::request; 13 | use axum::{body::Body, http::StatusCode}; 14 | 15 | #[tokio::test] 16 | async fn index() { 17 | let app = router::router(); 18 | let response = request(app, "/", Body::empty()).await; 19 | assert_eq!(response.status(), StatusCode::OK); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/controllers/posts.rs: -------------------------------------------------------------------------------- 1 | use crate::error::Result; 2 | use crate::models::post::PostList; 3 | use crate::repositories::{post::PostRepo, RepoExt, Repositories}; 4 | use axum::{extract::Extension, http::StatusCode, Json}; 5 | 6 | pub async fn index(Extension(repo): RepoExt) -> Result> { 7 | let posts = repo.post().find_all().await?; 8 | Ok(Json(posts)) 9 | } 10 | 11 | pub async fn add() -> StatusCode { 12 | StatusCode::OK 13 | } 14 | 15 | pub async fn view() -> StatusCode { 16 | StatusCode::OK 17 | } 18 | 19 | pub async fn edit() -> StatusCode { 20 | StatusCode::OK 21 | } 22 | 23 | pub async fn delete() -> StatusCode { 24 | StatusCode::OK 25 | } 26 | -------------------------------------------------------------------------------- /src/controllers/users.rs: -------------------------------------------------------------------------------- 1 | use crate::error::{AppError, Result}; 2 | use crate::models::user::{NewUser, User, UserConditions, UserId, UserList}; 3 | use crate::repositories::RepoExt; 4 | use crate::services::img_upload::img_upload; 5 | use crate::usecases; 6 | use anyhow::anyhow; 7 | use axum::{ 8 | extract::{ContentLengthLimit, Extension, Multipart, Path, Query}, 9 | http::StatusCode, 10 | Json, 11 | }; 12 | 13 | pub async fn index( 14 | Query(conditions): Query, 15 | Extension(repo): RepoExt, 16 | ) -> Result> { 17 | let users = usecases::users::search(repo.clone(), &conditions).await?; 18 | Ok(Json(users)) 19 | } 20 | 21 | pub async fn view(Path(user_id): Path, Extension(repo): RepoExt) -> Result> { 22 | let user = usecases::users::view(repo.clone(), user_id).await?; 23 | Ok(Json(user)) 24 | } 25 | 26 | pub async fn add(Json(new_user): Json, Extension(repo): RepoExt) -> Result> { 27 | let user_id = usecases::users::add(repo.clone(), &new_user).await?; 28 | Ok(Json(user_id)) 29 | } 30 | 31 | pub async fn edit_prof_img( 32 | ContentLengthLimit(multipart): ContentLengthLimit, 33 | Extension(repo): RepoExt, 34 | ) -> Result> { 35 | let result = _multipart_for_edit_prof_img(multipart).await; 36 | if let Err(e) = result { 37 | return Err(AppError::MultipartError(e.to_string())); 38 | } 39 | let (user_id, prof_img) = result.unwrap(); 40 | let result = img_upload(prof_img, "/"); 41 | println!("user_id: {user_id} upload result {result:?}"); 42 | let user = usecases::users::view(repo.clone(), 10).await?; 43 | Ok(Json(user)) 44 | } 45 | 46 | async fn _multipart_for_edit_prof_img(mut multipart: Multipart) -> anyhow::Result<(i32, Vec)> { 47 | let mut user_id: Option = None; 48 | let mut prof_img: Vec = vec![]; 49 | while let Some(field) = multipart.next_field().await? { 50 | let name = field.name().unwrap_or("").to_string(); 51 | let bytes: Vec = field.bytes().await?.into_iter().collect(); 52 | match &*name { 53 | "user_id" => user_id = Some(std::str::from_utf8(&bytes)?.parse()?), 54 | "prof_img" => prof_img = bytes, 55 | _ => return Err(anyhow!("Invalid Parameter")), 56 | } 57 | } 58 | Ok((user_id.unwrap(), prof_img)) 59 | } 60 | 61 | pub async fn edit() -> StatusCode { 62 | StatusCode::OK 63 | } 64 | 65 | pub async fn delete() -> StatusCode { 66 | StatusCode::OK 67 | } 68 | -------------------------------------------------------------------------------- /src/db/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod postgres; 2 | -------------------------------------------------------------------------------- /src/db/postgres/mod.rs: -------------------------------------------------------------------------------- 1 | use dotenv::dotenv; 2 | use sqlx::{postgres::PgPoolOptions, Pool, Postgres}; 3 | use std::env; 4 | use std::sync::Arc; 5 | 6 | pub type Db = Arc>; 7 | 8 | pub async fn db_connect() -> Pool { 9 | dotenv().ok(); 10 | let db_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); 11 | PgPoolOptions::new() 12 | .max_connections(5) 13 | .connect(&db_url) 14 | .await 15 | .expect("Error connecting to database") 16 | } 17 | -------------------------------------------------------------------------------- /src/error/mod.rs: -------------------------------------------------------------------------------- 1 | use axum::{ 2 | http::StatusCode, 3 | response::{IntoResponse, Response}, 4 | Json, 5 | }; 6 | use serde_json::json; 7 | use thiserror::Error; 8 | 9 | pub type Result = core::result::Result; 10 | 11 | #[derive(Debug, Error)] 12 | pub enum AppError { 13 | #[allow(dead_code)] 14 | #[error("Not Found: {0}")] 15 | NotFound(&'static str), 16 | #[allow(dead_code)] 17 | #[error("Invalid params: {0:?}")] 18 | InvalidParams(Vec<&'static str>), 19 | #[error("Invalid file format")] 20 | InvalidFileFormat, 21 | #[error("Error parsing `multipart/form-data` request.\n{0}")] 22 | MultipartError(String), 23 | #[error(transparent)] 24 | Other(#[from] anyhow::Error), 25 | } 26 | 27 | impl IntoResponse for AppError { 28 | fn into_response(self) -> Response { 29 | let (status, err_msg) = match self { 30 | AppError::NotFound(_) => (StatusCode::NOT_FOUND, self.to_string()), 31 | AppError::InvalidParams(_) => (StatusCode::UNPROCESSABLE_ENTITY, self.to_string()), 32 | AppError::MultipartError(_) => (StatusCode::UNPROCESSABLE_ENTITY, self.to_string()), 33 | AppError::InvalidFileFormat => (StatusCode::UNPROCESSABLE_ENTITY, self.to_string()), 34 | AppError::Other(_) => (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()), 35 | }; 36 | let body = Json(json!({ 37 | "error": err_msg, 38 | })); 39 | (status, body).into_response() 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::net::SocketAddr; 2 | 3 | mod bootstrap; 4 | mod controllers; 5 | mod db; 6 | mod error; 7 | mod models; 8 | mod repositories; 9 | mod router; 10 | mod services; 11 | #[cfg(test)] 12 | mod tests; 13 | mod usecases; 14 | 15 | #[tokio::main] 16 | async fn main() { 17 | tracing_subscriber::fmt::init(); 18 | let addr = SocketAddr::from(([0, 0, 0, 0], 8080)); 19 | tracing::debug!("listening on {}", addr); 20 | let app = bootstrap::create_app().await; 21 | axum::Server::bind(&addr) 22 | .serve(app.into_make_service()) 23 | .await 24 | .unwrap(); 25 | } 26 | -------------------------------------------------------------------------------- /src/models/category.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use sqlx::FromRow; 3 | 4 | #[derive(Serialize, Deserialize, sqlx::FromRow)] 5 | pub struct Category { 6 | pub id: i32, 7 | pub name: String, 8 | } 9 | 10 | pub type CategoryList = Vec; 11 | 12 | #[derive(Serialize, Deserialize, Debug)] 13 | pub struct CreateCategory { 14 | pub name: String, 15 | } 16 | 17 | #[derive(Serialize, Deserialize, Debug)] 18 | pub struct CategoryConditions { 19 | pub name: Option, 20 | } 21 | 22 | #[derive(Serialize, Deserialize, Debug, FromRow)] 23 | pub struct CategoryId { 24 | pub id: i32, 25 | } 26 | -------------------------------------------------------------------------------- /src/models/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod category; 2 | pub mod post; 3 | pub mod user; 4 | -------------------------------------------------------------------------------- /src/models/post.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | #[derive(Serialize, Deserialize, sqlx::FromRow)] 4 | pub struct Post { 5 | pub id: i32, 6 | pub user_id: i32, 7 | pub category_id: i32, 8 | pub title: String, 9 | pub content: String, 10 | } 11 | 12 | pub type PostList = Vec; 13 | -------------------------------------------------------------------------------- /src/models/user.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use sqlx::FromRow; 3 | 4 | #[derive(Serialize, Deserialize, FromRow, Debug)] 5 | pub struct User { 6 | pub id: i32, 7 | pub name: String, 8 | pub msg: Option, 9 | pub age: Option, 10 | } 11 | 12 | pub type UserList = Vec; 13 | 14 | #[derive(Serialize, Deserialize, Debug)] 15 | pub struct NewUser { 16 | pub name: String, 17 | pub msg: Option, 18 | pub age: Option, 19 | } 20 | 21 | #[derive(Serialize, Deserialize, Debug)] 22 | pub struct UserConditions { 23 | pub name: Option, 24 | } 25 | 26 | #[derive(Serialize, Deserialize, Debug, FromRow)] 27 | pub struct UserId { 28 | pub id: i32, 29 | } 30 | 31 | #[derive(Serialize)] 32 | pub struct ProfImg { 33 | pub user_id: i32, 34 | pub prof_img: Vec, 35 | } 36 | 37 | #[derive(Serialize, Deserialize, Debug, FromRow)] 38 | pub struct ImgUrl { 39 | pub url: String, 40 | } 41 | -------------------------------------------------------------------------------- /src/repositories/category.rs: -------------------------------------------------------------------------------- 1 | use crate::db::postgres::Db; 2 | use crate::error::Result; 3 | use crate::models::category::{ 4 | Category, CategoryConditions, CategoryId, CategoryList, CreateCategory, 5 | }; 6 | use anyhow::Context; 7 | use async_trait::async_trait; 8 | use mockall::automock; 9 | 10 | pub struct CategoryRepoImpl { 11 | pool: Db, 12 | } 13 | impl CategoryRepoImpl { 14 | pub fn new(pool: Db) -> Self { 15 | Self { pool: pool } 16 | } 17 | } 18 | 19 | #[automock] 20 | #[async_trait] 21 | pub trait CategoryRepo { 22 | async fn find_all(&self, conditions: &CategoryConditions) -> Result; 23 | async fn add(&self, category_data: &CreateCategory) -> Result; 24 | async fn find_by_id(&self, category_id: i32) -> Result; 25 | } 26 | 27 | #[async_trait] 28 | impl CategoryRepo for CategoryRepoImpl { 29 | async fn find_all(&self, conditions: &CategoryConditions) -> Result { 30 | let mut query = sqlx::query_as::<_, Category>("select * from categories"); 31 | if let Some(name) = &conditions.name { 32 | query = sqlx::query_as::<_, Category>("select * from categories where name LIKE $1") 33 | .bind(format!("%{}%", name)) 34 | } 35 | let result = query 36 | .fetch_all(&*self.pool) 37 | .await 38 | .context("DB ERROR (find add categories)")?; 39 | Ok(result) 40 | } 41 | 42 | async fn add(&self, category_data: &CreateCategory) -> Result { 43 | let row = sqlx::query_as::<_, CategoryId>( 44 | r#" 45 | INSERT INTO categories (name) 46 | VALUES ($1) 47 | RETURNING id 48 | "#, 49 | ) 50 | .bind(&category_data.name) 51 | .fetch_one(&*self.pool) 52 | .await 53 | .context("DB ERROR (create category)")?; 54 | Ok(row) 55 | } 56 | 57 | async fn find_by_id(&self, category_id: i32) -> Result { 58 | let row = sqlx::query_as::<_, Category>("select * from categories where id = $1") 59 | .bind(category_id) 60 | .fetch_one(&*self.pool) 61 | .await 62 | .context("DB ERROR (find category by id)")?; 63 | Ok(row) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/repositories/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::db::postgres; 2 | use crate::repositories::{ 3 | category::{CategoryRepo, CategoryRepoImpl}, 4 | post::{PostRepo, PostRepoImpl}, 5 | user::{UserRepo, UserRepoImpl}, 6 | }; 7 | use axum::extract::Extension; 8 | use std::sync::Arc; 9 | 10 | pub mod category; 11 | pub mod post; 12 | pub mod user; 13 | 14 | pub type RepoExt = Extension>; 15 | 16 | pub async fn create_repositories() -> RepoImpls { 17 | let db_pool = Arc::new(postgres::db_connect().await); 18 | RepoImpls::new( 19 | UserRepoImpl::new(db_pool.clone()), 20 | CategoryRepoImpl::new(db_pool.clone()), 21 | PostRepoImpl::new(db_pool.clone()), 22 | ) 23 | } 24 | 25 | pub struct RepoImpls { 26 | pub user: UserRepoImpl, 27 | pub category: CategoryRepoImpl, 28 | pub post: PostRepoImpl, 29 | } 30 | impl RepoImpls { 31 | pub fn new( 32 | user_repo_impl: UserRepoImpl, 33 | category_repo_impl: CategoryRepoImpl, 34 | post_repo_impl: PostRepoImpl, 35 | ) -> Self { 36 | Self { 37 | user: user_repo_impl, 38 | category: category_repo_impl, 39 | post: post_repo_impl, 40 | } 41 | } 42 | } 43 | 44 | pub trait Repositories { 45 | type UserRepoImpl: UserRepo; 46 | type CategoryRepoImpl: CategoryRepo; 47 | type PostRepoImpl: PostRepo; 48 | fn user(&self) -> &Self::UserRepoImpl; 49 | fn category(&self) -> &Self::CategoryRepoImpl; 50 | fn post(&self) -> &Self::PostRepoImpl; 51 | } 52 | impl Repositories for RepoImpls { 53 | type UserRepoImpl = UserRepoImpl; 54 | type CategoryRepoImpl = CategoryRepoImpl; 55 | type PostRepoImpl = PostRepoImpl; 56 | fn user(&self) -> &Self::UserRepoImpl { 57 | &self.user 58 | } 59 | fn category(&self) -> &Self::CategoryRepoImpl { 60 | &self.category 61 | } 62 | fn post(&self) -> &Self::PostRepoImpl { 63 | &self.post 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/repositories/post.rs: -------------------------------------------------------------------------------- 1 | use crate::db::postgres::Db; 2 | use crate::error::Result; 3 | use crate::models::post::{Post, PostList}; 4 | use anyhow::Context; 5 | use async_trait::async_trait; 6 | use mockall::automock; 7 | 8 | pub struct PostRepoImpl { 9 | pool: Db, 10 | } 11 | impl PostRepoImpl { 12 | pub fn new(pool: Db) -> Self { 13 | Self { pool: pool } 14 | } 15 | } 16 | 17 | #[automock] 18 | #[async_trait] 19 | pub trait PostRepo { 20 | async fn find_all(&self) -> Result; 21 | } 22 | 23 | #[async_trait] 24 | impl PostRepo for PostRepoImpl { 25 | async fn find_all(&self) -> Result { 26 | let result = sqlx::query_as::<_, Post>("select * from posts") 27 | .fetch_all(&*self.pool) 28 | .await 29 | .context("DB ERROR (find all posts)")?; 30 | Ok(result) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/repositories/user.rs: -------------------------------------------------------------------------------- 1 | use crate::db::postgres::Db; 2 | use crate::error::Result; 3 | use crate::models::user::{NewUser, User, UserConditions, UserId, UserList}; 4 | use anyhow::Context; 5 | use async_trait::async_trait; 6 | use mockall::automock; 7 | 8 | pub struct UserRepoImpl { 9 | pool: Db, 10 | } 11 | impl UserRepoImpl { 12 | pub fn new(pool: Db) -> Self { 13 | Self { pool: pool } 14 | } 15 | } 16 | 17 | #[automock] 18 | #[async_trait] 19 | pub trait UserRepo { 20 | async fn find_all(&self, conditions: &UserConditions) -> Result; 21 | async fn add(&self, user_data: &NewUser) -> Result; 22 | async fn find_by_id(&self, user_id: i32) -> Result; 23 | } 24 | 25 | #[async_trait] 26 | impl UserRepo for UserRepoImpl { 27 | async fn find_all(&self, conditions: &UserConditions) -> Result { 28 | let mut query = sqlx::query_as::<_, User>("select * from users"); 29 | if let Some(name) = &conditions.name { 30 | query = sqlx::query_as::<_, User>("select * from users where name LIKE $1") 31 | .bind(format!("%{}%", name)) 32 | } 33 | let result = query 34 | .fetch_all(&*self.pool) 35 | .await 36 | .context("DB ERROR (find all users)")?; 37 | Ok(result) 38 | } 39 | 40 | async fn add(&self, user_data: &NewUser) -> Result { 41 | let row = sqlx::query_as::<_, UserId>( 42 | r#" 43 | INSERT INTO users (name, msg, age) 44 | VALUES ($1, $2, $3) 45 | RETURNING id 46 | "#, 47 | ) 48 | .bind(&user_data.name) 49 | .bind(&user_data.msg) 50 | .bind(&user_data.age) 51 | .fetch_one(&*self.pool) 52 | .await 53 | .context("DB ERROR (create user)")?; 54 | Ok(row) 55 | } 56 | 57 | async fn find_by_id(&self, user_id: i32) -> Result { 58 | let row = sqlx::query_as::<_, User>("select * from users where id = $1") 59 | .bind(user_id) 60 | .fetch_one(&*self.pool) 61 | .await 62 | .context("DB ERROR (find user by id)")?; 63 | Ok(row) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/router/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::controllers::{categories, posts, root, users}; 2 | use axum::{ 3 | routing::{get, post}, 4 | Router, 5 | }; 6 | 7 | pub fn router() -> Router { 8 | Router::new() 9 | .route("/", get(root)) 10 | .nest("/users", user_routes()) 11 | .nest("/categories", category_routes()) 12 | .nest("/posts", post_routes()) 13 | } 14 | 15 | fn user_routes() -> Router { 16 | Router::new() 17 | .route("/", get(users::index)) 18 | .route("/view/:user_id", get(users::view)) 19 | .route("/add", post(users::add)) 20 | .route("/edit", post(users::edit)) 21 | .route("/edit/img/prof", post(users::edit_prof_img)) 22 | .route("/delete", post(users::delete)) 23 | } 24 | 25 | fn category_routes() -> Router { 26 | Router::new() 27 | .route("/", get(categories::index)) 28 | .route("/view/:category_id", get(categories::view)) 29 | .route("/add", post(categories::add)) 30 | .route("/edit", post(categories::edit)) 31 | .route("/delete", post(categories::delete)) 32 | } 33 | 34 | fn post_routes() -> Router { 35 | Router::new() 36 | .route("/", get(posts::index)) 37 | .route("/view/:post_id", get(posts::view)) 38 | .route("/add", post(posts::add)) 39 | .route("/edit", post(posts::edit)) 40 | .route("/delete", post(posts::delete)) 41 | } 42 | -------------------------------------------------------------------------------- /src/services/img_upload.rs: -------------------------------------------------------------------------------- 1 | use crate::error::{AppError, Result}; 2 | use exif::{In, Reader, Tag}; 3 | use image::{guess_format, ImageFormat, DynamicImage}; 4 | use std::fs::File; 5 | use std::io::Cursor; 6 | use uuid::Uuid; 7 | 8 | pub fn img_upload(img_bytes: Vec, save_path:&'static str) -> Result<()> { 9 | let orientation = get_orientation(&img_bytes); 10 | println!("orientaiton {orientation}"); 11 | let (format, ext) = get_format_and_ext(&img_bytes)?; 12 | let file_name = create_file_name(&ext); 13 | match image::load_from_memory_with_format(&img_bytes, format) { 14 | Ok(img) => { 15 | let mut new_img = img.thumbnail(300, 300); 16 | new_img = img_rotate(new_img, orientation); 17 | let mut output = File::create(file_name).unwrap(); 18 | new_img.write_to(&mut output, format).unwrap(); 19 | } 20 | Err(_) => return Err(AppError::InvalidFileFormat), 21 | } 22 | Ok(()) 23 | } 24 | 25 | pub fn img_rotate(img:DynamicImage, orientation:u32) -> DynamicImage { 26 | let img = match orientation { 27 | 1 => img, 28 | 2 => img.flipv(), 29 | 3 => img.rotate180(), 30 | 4 => img.fliph(), 31 | 5 => img.flipv().rotate270(), 32 | 6 => img.rotate90(), 33 | 7 => img.flipv().rotate90(), 34 | 8 => img.rotate270(), 35 | _ => img 36 | }; 37 | img 38 | } 39 | 40 | pub fn get_orientation(img_bytes: &Vec) -> u32 { 41 | let mut buf = Cursor::new(img_bytes); 42 | let mut orientation = 1; 43 | if let Ok(exif) = Reader::new().read_from_container(&mut buf) { 44 | if let Some(o) = exif.get_field(Tag::Orientation, In::PRIMARY) { 45 | if let Some(v @ 1..=8) = o.value.get_uint(0) { 46 | orientation = v; 47 | } 48 | } 49 | } 50 | orientation 51 | } 52 | 53 | pub fn get_format_and_ext(img_bytes: &Vec) -> Result<(ImageFormat, &'static str)> { 54 | match guess_format(img_bytes) { 55 | Ok(ImageFormat::Png) => return Ok((ImageFormat::Png, "png")), 56 | Ok(ImageFormat::Jpeg) => return Ok((ImageFormat::Jpeg, "jpg")), 57 | Ok(ImageFormat::Gif) => return Ok((ImageFormat::Gif, "gif")), 58 | _ => return Err(AppError::InvalidFileFormat), 59 | }; 60 | } 61 | 62 | pub fn create_file_name(ext:&'static str) -> String { 63 | format!("{}.{}", Uuid::new_v4().to_hyphenated(), ext) 64 | } 65 | 66 | pub fn save_gcp() { 67 | 68 | } -------------------------------------------------------------------------------- /src/services/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod img_upload; 2 | -------------------------------------------------------------------------------- /src/tests/fixture/category.rs: -------------------------------------------------------------------------------- 1 | use crate::models::category::Category; 2 | 3 | #[allow(dead_code)] 4 | pub fn category_fixture(id: usize) -> Category { 5 | Category { 6 | id: id as i32, 7 | name: String::from("food"), 8 | } 9 | } 10 | 11 | #[allow(dead_code)] 12 | pub fn categoies_fixture(num: usize) -> Vec { 13 | let mut categories = vec![]; 14 | for i in 1..num + 1 { 15 | categories.push(category_fixture(i)); 16 | } 17 | categories 18 | } 19 | -------------------------------------------------------------------------------- /src/tests/fixture/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod category; 2 | pub mod post; 3 | pub mod user; 4 | -------------------------------------------------------------------------------- /src/tests/fixture/post.rs: -------------------------------------------------------------------------------- 1 | use crate::models::post::Post; 2 | 3 | #[allow(dead_code)] 4 | pub fn post_fixture(id: usize) -> Post { 5 | Post { 6 | id: id as i32, 7 | user_id: 1, 8 | category_id: 1, 9 | title: String::from("post1"), 10 | content: String::from("content1"), 11 | } 12 | } 13 | 14 | #[allow(dead_code)] 15 | pub fn posts_fixture(num: usize) -> Vec { 16 | let mut posts = vec![]; 17 | for i in 1..num + 1 { 18 | posts.push(post_fixture(i)); 19 | } 20 | posts 21 | } 22 | -------------------------------------------------------------------------------- /src/tests/fixture/user.rs: -------------------------------------------------------------------------------- 1 | use crate::models::user::User; 2 | 3 | #[allow(dead_code)] 4 | pub fn user_fixture(id: usize) -> User { 5 | User { 6 | id: id as i32, 7 | name: String::from("taro"), 8 | msg: Some(String::from("hello")), 9 | age: Some(20), 10 | } 11 | } 12 | 13 | #[allow(dead_code)] 14 | pub fn users_fixture(num: usize) -> Vec { 15 | let mut users = vec![]; 16 | for i in 1..num + 1 { 17 | users.push(user_fixture(i)); 18 | } 19 | users 20 | } 21 | -------------------------------------------------------------------------------- /src/tests/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod fixture; 2 | pub mod repositories; 3 | 4 | use axum::{body::Body, http::Request, response::Response, Router}; 5 | use tower::util::ServiceExt; 6 | 7 | pub async fn request(app: Router, url: &'static str, body: Body) -> Response { 8 | app.oneshot(Request::builder().uri(url).body(body).unwrap()) 9 | .await 10 | .unwrap() 11 | } 12 | -------------------------------------------------------------------------------- /src/tests/repositories/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::repositories::{ 2 | category::MockCategoryRepo as MockCategoryRepoImpl, post::MockPostRepo as MockPostRepoImpl, 3 | user::MockUserRepo as MockUserRepoImpl, Repositories, 4 | }; 5 | 6 | pub async fn create_repositories_for_test() -> MockRepoImpls { 7 | MockRepoImpls::new( 8 | MockUserRepoImpl::new(), 9 | MockCategoryRepoImpl::new(), 10 | MockPostRepoImpl::new(), 11 | ) 12 | } 13 | 14 | #[derive(Debug)] 15 | pub struct MockRepoImpls { 16 | pub user: MockUserRepoImpl, 17 | pub category: MockCategoryRepoImpl, 18 | pub post: MockPostRepoImpl, 19 | } 20 | impl MockRepoImpls { 21 | pub fn new( 22 | mock_user_repo_impl: MockUserRepoImpl, 23 | mock_category_repo_impl: MockCategoryRepoImpl, 24 | mock_post_repo_impl: MockPostRepoImpl, 25 | ) -> Self { 26 | Self { 27 | user: mock_user_repo_impl, 28 | category: mock_category_repo_impl, 29 | post: mock_post_repo_impl, 30 | } 31 | } 32 | } 33 | impl Repositories for MockRepoImpls { 34 | type UserRepoImpl = MockUserRepoImpl; 35 | type CategoryRepoImpl = MockCategoryRepoImpl; 36 | type PostRepoImpl = MockPostRepoImpl; 37 | fn user(&self) -> &Self::UserRepoImpl { 38 | &self.user 39 | } 40 | fn category(&self) -> &Self::CategoryRepoImpl { 41 | &self.category 42 | } 43 | fn post(&self) -> &Self::PostRepoImpl { 44 | &self.post 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/usecases/categories.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/usecases/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod categories; 2 | pub mod posts; 3 | pub mod users; 4 | -------------------------------------------------------------------------------- /src/usecases/posts.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/usecases/users.rs: -------------------------------------------------------------------------------- 1 | use crate::error::Result; 2 | use crate::models::user::{ImgUrl, NewUser, ProfImg, User, UserConditions, UserId, UserList}; 3 | use crate::repositories::{user::UserRepo, Repositories}; 4 | use std::sync::Arc; 5 | 6 | pub async fn search( 7 | repo: Arc, 8 | conditions: &UserConditions, 9 | ) -> Result { 10 | let users = repo.user().find_all(conditions).await?; 11 | Ok(users) 12 | } 13 | 14 | pub async fn view(repo: Arc, user_id: i32) -> Result { 15 | let user = repo.user().find_by_id(user_id).await?; 16 | Ok(user) 17 | } 18 | 19 | pub async fn add(repo: Arc, new_user: &NewUser) -> Result { 20 | let user_id = repo.user().add(&new_user).await?; 21 | Ok(user_id) 22 | } 23 | 24 | pub async fn edit_prof_img(_repo: Arc, _prof_img: &ProfImg) -> Result { 25 | Ok(ImgUrl { 26 | url: String::from("https://example.com/hoge.png"), 27 | }) 28 | } 29 | 30 | #[cfg(test)] 31 | mod tests { 32 | use super::*; 33 | use crate::tests::{fixture::user::users_fixture, repositories::create_repositories_for_test}; 34 | 35 | #[tokio::test] 36 | async fn test_search() { 37 | let mut mock_repo_impl = create_repositories_for_test().await; 38 | mock_repo_impl 39 | .user 40 | .expect_find_all() 41 | .returning(|_| Ok(users_fixture(5))); 42 | let conditions = UserConditions { name: None }; 43 | let users = search(Arc::new(mock_repo_impl), &conditions).await.unwrap(); 44 | assert_eq!(users.len(), 5); 45 | } 46 | } 47 | --------------------------------------------------------------------------------