├── .editorconfig ├── .env.example ├── .envrc ├── .github └── FUNDING.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── Makefile ├── Procfile ├── README.md ├── api └── todos.graphql ├── diesel.toml ├── docker-compose.yml ├── flake.lock ├── flake.nix ├── migrations ├── 00000000000000_diesel_initial_setup │ ├── down.sql │ └── up.sql └── 2019-12-27-225611_create_todos │ ├── down.sql │ └── up.sql ├── rust-toolchain.toml ├── rustfmt.toml └── src ├── context.rs ├── data.rs ├── db.rs ├── endpoints.rs ├── graphql.rs ├── lib.rs ├── main.rs ├── models.rs └── schema.rs /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | 7 | [Makefile] 8 | indent_style = tab 9 | 10 | [*.{graphql,sql,toml}] 11 | indent_style = space 12 | indent_size = 2 13 | 14 | [*.rs] 15 | indent_style = space 16 | indent_size = 4 17 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | DATABASE_URL=postgres://localhost:5432/todos 2 | POSTGRES_USER=user 3 | POSTGRES_PASSWORD=example 4 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | use flake 2 | 3 | dotenv 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [lucperkins] 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /.direnv 3 | .env 4 | -------------------------------------------------------------------------------- /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 = "actix-codec" 7 | version = "0.2.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "09e55f0a5c2ca15795035d90c46bd0e73a5123b72f68f12596d6ba5282051380" 10 | dependencies = [ 11 | "bitflags", 12 | "bytes 0.5.6", 13 | "futures-core", 14 | "futures-sink", 15 | "log", 16 | "tokio", 17 | "tokio-util 0.2.0", 18 | ] 19 | 20 | [[package]] 21 | name = "actix-codec" 22 | version = "0.3.0" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "78d1833b3838dbe990df0f1f87baf640cf6146e898166afe401839d1b001e570" 25 | dependencies = [ 26 | "bitflags", 27 | "bytes 0.5.6", 28 | "futures-core", 29 | "futures-sink", 30 | "log", 31 | "pin-project 0.4.30", 32 | "tokio", 33 | "tokio-util 0.3.1", 34 | ] 35 | 36 | [[package]] 37 | name = "actix-connect" 38 | version = "1.0.2" 39 | source = "registry+https://github.com/rust-lang/crates.io-index" 40 | checksum = "c95cc9569221e9802bf4c377f6c18b90ef10227d787611decf79fd47d2a8e76c" 41 | dependencies = [ 42 | "actix-codec 0.2.0", 43 | "actix-rt", 44 | "actix-service", 45 | "actix-utils 1.0.6", 46 | "derive_more", 47 | "either", 48 | "futures", 49 | "http", 50 | "log", 51 | "trust-dns-proto", 52 | "trust-dns-resolver", 53 | ] 54 | 55 | [[package]] 56 | name = "actix-http" 57 | version = "1.0.1" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "c16664cc4fdea8030837ad5a845eb231fb93fc3c5c171edfefb52fad92ce9019" 60 | dependencies = [ 61 | "actix-codec 0.2.0", 62 | "actix-connect", 63 | "actix-rt", 64 | "actix-service", 65 | "actix-threadpool", 66 | "actix-utils 1.0.6", 67 | "base64", 68 | "bitflags", 69 | "brotli2", 70 | "bytes 0.5.6", 71 | "chrono", 72 | "copyless", 73 | "derive_more", 74 | "either", 75 | "encoding_rs", 76 | "failure", 77 | "flate2", 78 | "futures-channel", 79 | "futures-core", 80 | "futures-util", 81 | "fxhash", 82 | "h2", 83 | "http", 84 | "httparse", 85 | "indexmap", 86 | "language-tags", 87 | "lazy_static", 88 | "log", 89 | "mime", 90 | "percent-encoding", 91 | "pin-project 0.4.30", 92 | "rand", 93 | "regex", 94 | "serde", 95 | "serde_json", 96 | "serde_urlencoded", 97 | "sha1", 98 | "slab", 99 | "time", 100 | ] 101 | 102 | [[package]] 103 | name = "actix-macros" 104 | version = "0.1.3" 105 | source = "registry+https://github.com/rust-lang/crates.io-index" 106 | checksum = "b4ca8ce00b267af8ccebbd647de0d61e0674b6e61185cc7a592ff88772bed655" 107 | dependencies = [ 108 | "quote", 109 | "syn", 110 | ] 111 | 112 | [[package]] 113 | name = "actix-router" 114 | version = "0.2.7" 115 | source = "registry+https://github.com/rust-lang/crates.io-index" 116 | checksum = "2ad299af73649e1fc893e333ccf86f377751eb95ff875d095131574c6f43452c" 117 | dependencies = [ 118 | "bytestring", 119 | "http", 120 | "log", 121 | "regex", 122 | "serde", 123 | ] 124 | 125 | [[package]] 126 | name = "actix-rt" 127 | version = "1.1.1" 128 | source = "registry+https://github.com/rust-lang/crates.io-index" 129 | checksum = "143fcc2912e0d1de2bcf4e2f720d2a60c28652ab4179685a1ee159e0fb3db227" 130 | dependencies = [ 131 | "actix-macros", 132 | "actix-threadpool", 133 | "copyless", 134 | "futures-channel", 135 | "futures-util", 136 | "smallvec", 137 | "tokio", 138 | ] 139 | 140 | [[package]] 141 | name = "actix-server" 142 | version = "1.0.4" 143 | source = "registry+https://github.com/rust-lang/crates.io-index" 144 | checksum = "45407e6e672ca24784baa667c5d32ef109ccdd8d5e0b5ebb9ef8a67f4dfb708e" 145 | dependencies = [ 146 | "actix-codec 0.3.0", 147 | "actix-rt", 148 | "actix-service", 149 | "actix-utils 2.0.0", 150 | "futures-channel", 151 | "futures-util", 152 | "log", 153 | "mio", 154 | "mio-uds", 155 | "num_cpus", 156 | "slab", 157 | "socket2", 158 | ] 159 | 160 | [[package]] 161 | name = "actix-service" 162 | version = "1.0.6" 163 | source = "registry+https://github.com/rust-lang/crates.io-index" 164 | checksum = "0052435d581b5be835d11f4eb3bce417c8af18d87ddf8ace99f8e67e595882bb" 165 | dependencies = [ 166 | "futures-util", 167 | "pin-project 0.4.30", 168 | ] 169 | 170 | [[package]] 171 | name = "actix-testing" 172 | version = "1.0.1" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | checksum = "47239ca38799ab74ee6a8a94d1ce857014b2ac36f242f70f3f75a66f691e791c" 175 | dependencies = [ 176 | "actix-macros", 177 | "actix-rt", 178 | "actix-server", 179 | "actix-service", 180 | "log", 181 | "socket2", 182 | ] 183 | 184 | [[package]] 185 | name = "actix-threadpool" 186 | version = "0.3.3" 187 | source = "registry+https://github.com/rust-lang/crates.io-index" 188 | checksum = "d209f04d002854b9afd3743032a27b066158817965bf5d036824d19ac2cc0e30" 189 | dependencies = [ 190 | "derive_more", 191 | "futures-channel", 192 | "lazy_static", 193 | "log", 194 | "num_cpus", 195 | "parking_lot 0.11.2", 196 | "threadpool", 197 | ] 198 | 199 | [[package]] 200 | name = "actix-tls" 201 | version = "1.0.0" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "a4e5b4faaf105e9a6d389c606c298dcdb033061b00d532af9df56ff3a54995a8" 204 | dependencies = [ 205 | "actix-codec 0.2.0", 206 | "actix-rt", 207 | "actix-service", 208 | "actix-utils 1.0.6", 209 | "derive_more", 210 | "either", 211 | "futures", 212 | "log", 213 | ] 214 | 215 | [[package]] 216 | name = "actix-utils" 217 | version = "1.0.6" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "fcf8f5631bf01adec2267808f00e228b761c60c0584cc9fa0b5364f41d147f4e" 220 | dependencies = [ 221 | "actix-codec 0.2.0", 222 | "actix-rt", 223 | "actix-service", 224 | "bitflags", 225 | "bytes 0.5.6", 226 | "either", 227 | "futures", 228 | "log", 229 | "pin-project 0.4.30", 230 | "slab", 231 | ] 232 | 233 | [[package]] 234 | name = "actix-utils" 235 | version = "2.0.0" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "2e9022dec56632d1d7979e59af14f0597a28a830a9c1c7fec8b2327eb9f16b5a" 238 | dependencies = [ 239 | "actix-codec 0.3.0", 240 | "actix-rt", 241 | "actix-service", 242 | "bitflags", 243 | "bytes 0.5.6", 244 | "either", 245 | "futures-channel", 246 | "futures-sink", 247 | "futures-util", 248 | "log", 249 | "pin-project 0.4.30", 250 | "slab", 251 | ] 252 | 253 | [[package]] 254 | name = "actix-web" 255 | version = "2.0.0" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "3158e822461040822f0dbf1735b9c2ce1f95f93b651d7a7aded00b1efbb1f635" 258 | dependencies = [ 259 | "actix-codec 0.2.0", 260 | "actix-http", 261 | "actix-macros", 262 | "actix-router", 263 | "actix-rt", 264 | "actix-server", 265 | "actix-service", 266 | "actix-testing", 267 | "actix-threadpool", 268 | "actix-tls", 269 | "actix-utils 1.0.6", 270 | "actix-web-codegen", 271 | "awc", 272 | "bytes 0.5.6", 273 | "derive_more", 274 | "encoding_rs", 275 | "futures", 276 | "fxhash", 277 | "log", 278 | "mime", 279 | "net2", 280 | "pin-project 0.4.30", 281 | "regex", 282 | "serde", 283 | "serde_json", 284 | "serde_urlencoded", 285 | "time", 286 | "url", 287 | ] 288 | 289 | [[package]] 290 | name = "actix-web-codegen" 291 | version = "0.2.2" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "a71bf475cbe07281d0b3696abb48212db118e7e23219f13596ce865235ff5766" 294 | dependencies = [ 295 | "proc-macro2", 296 | "quote", 297 | "syn", 298 | ] 299 | 300 | [[package]] 301 | name = "addr2line" 302 | version = "0.17.0" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" 305 | dependencies = [ 306 | "gimli", 307 | ] 308 | 309 | [[package]] 310 | name = "adler" 311 | version = "1.0.2" 312 | source = "registry+https://github.com/rust-lang/crates.io-index" 313 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 314 | 315 | [[package]] 316 | name = "aho-corasick" 317 | version = "0.7.19" 318 | source = "registry+https://github.com/rust-lang/crates.io-index" 319 | checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" 320 | dependencies = [ 321 | "memchr", 322 | ] 323 | 324 | [[package]] 325 | name = "android_system_properties" 326 | version = "0.1.5" 327 | source = "registry+https://github.com/rust-lang/crates.io-index" 328 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 329 | dependencies = [ 330 | "libc", 331 | ] 332 | 333 | [[package]] 334 | name = "async-trait" 335 | version = "0.1.57" 336 | source = "registry+https://github.com/rust-lang/crates.io-index" 337 | checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f" 338 | dependencies = [ 339 | "proc-macro2", 340 | "quote", 341 | "syn", 342 | ] 343 | 344 | [[package]] 345 | name = "atty" 346 | version = "0.2.14" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 349 | dependencies = [ 350 | "hermit-abi", 351 | "libc", 352 | "winapi 0.3.9", 353 | ] 354 | 355 | [[package]] 356 | name = "autocfg" 357 | version = "1.1.0" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 360 | 361 | [[package]] 362 | name = "awc" 363 | version = "1.0.1" 364 | source = "registry+https://github.com/rust-lang/crates.io-index" 365 | checksum = "d7601d4d1d7ef2335d6597a41b5fe069f6ab799b85f53565ab390e7b7065aac5" 366 | dependencies = [ 367 | "actix-codec 0.2.0", 368 | "actix-http", 369 | "actix-rt", 370 | "actix-service", 371 | "base64", 372 | "bytes 0.5.6", 373 | "derive_more", 374 | "futures-core", 375 | "log", 376 | "mime", 377 | "percent-encoding", 378 | "rand", 379 | "serde", 380 | "serde_json", 381 | "serde_urlencoded", 382 | ] 383 | 384 | [[package]] 385 | name = "backtrace" 386 | version = "0.3.66" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7" 389 | dependencies = [ 390 | "addr2line", 391 | "cc", 392 | "cfg-if 1.0.0", 393 | "libc", 394 | "miniz_oxide", 395 | "object", 396 | "rustc-demangle", 397 | ] 398 | 399 | [[package]] 400 | name = "base64" 401 | version = "0.11.0" 402 | source = "registry+https://github.com/rust-lang/crates.io-index" 403 | checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" 404 | 405 | [[package]] 406 | name = "bitflags" 407 | version = "1.3.2" 408 | source = "registry+https://github.com/rust-lang/crates.io-index" 409 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 410 | 411 | [[package]] 412 | name = "brotli-sys" 413 | version = "0.3.2" 414 | source = "registry+https://github.com/rust-lang/crates.io-index" 415 | checksum = "4445dea95f4c2b41cde57cc9fee236ae4dbae88d8fcbdb4750fc1bb5d86aaecd" 416 | dependencies = [ 417 | "cc", 418 | "libc", 419 | ] 420 | 421 | [[package]] 422 | name = "brotli2" 423 | version = "0.3.2" 424 | source = "registry+https://github.com/rust-lang/crates.io-index" 425 | checksum = "0cb036c3eade309815c15ddbacec5b22c4d1f3983a774ab2eac2e3e9ea85568e" 426 | dependencies = [ 427 | "brotli-sys", 428 | "libc", 429 | ] 430 | 431 | [[package]] 432 | name = "bumpalo" 433 | version = "3.11.0" 434 | source = "registry+https://github.com/rust-lang/crates.io-index" 435 | checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" 436 | 437 | [[package]] 438 | name = "byteorder" 439 | version = "1.4.3" 440 | source = "registry+https://github.com/rust-lang/crates.io-index" 441 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 442 | 443 | [[package]] 444 | name = "bytes" 445 | version = "0.5.6" 446 | source = "registry+https://github.com/rust-lang/crates.io-index" 447 | checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" 448 | 449 | [[package]] 450 | name = "bytes" 451 | version = "1.2.1" 452 | source = "registry+https://github.com/rust-lang/crates.io-index" 453 | checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" 454 | 455 | [[package]] 456 | name = "bytestring" 457 | version = "1.1.0" 458 | source = "registry+https://github.com/rust-lang/crates.io-index" 459 | checksum = "86b6a75fd3048808ef06af5cd79712be8111960adaf89d90250974b38fc3928a" 460 | dependencies = [ 461 | "bytes 1.2.1", 462 | ] 463 | 464 | [[package]] 465 | name = "cc" 466 | version = "1.0.73" 467 | source = "registry+https://github.com/rust-lang/crates.io-index" 468 | checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" 469 | 470 | [[package]] 471 | name = "cfg-if" 472 | version = "0.1.10" 473 | source = "registry+https://github.com/rust-lang/crates.io-index" 474 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 475 | 476 | [[package]] 477 | name = "cfg-if" 478 | version = "1.0.0" 479 | source = "registry+https://github.com/rust-lang/crates.io-index" 480 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 481 | 482 | [[package]] 483 | name = "chrono" 484 | version = "0.4.22" 485 | source = "registry+https://github.com/rust-lang/crates.io-index" 486 | checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" 487 | dependencies = [ 488 | "iana-time-zone", 489 | "js-sys", 490 | "num-integer", 491 | "num-traits", 492 | "time", 493 | "wasm-bindgen", 494 | "winapi 0.3.9", 495 | ] 496 | 497 | [[package]] 498 | name = "convert_case" 499 | version = "0.4.0" 500 | source = "registry+https://github.com/rust-lang/crates.io-index" 501 | checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" 502 | 503 | [[package]] 504 | name = "copyless" 505 | version = "0.1.5" 506 | source = "registry+https://github.com/rust-lang/crates.io-index" 507 | checksum = "a2df960f5d869b2dd8532793fde43eb5427cceb126c929747a26823ab0eeb536" 508 | 509 | [[package]] 510 | name = "core-foundation-sys" 511 | version = "0.8.3" 512 | source = "registry+https://github.com/rust-lang/crates.io-index" 513 | checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" 514 | 515 | [[package]] 516 | name = "crc32fast" 517 | version = "1.3.2" 518 | source = "registry+https://github.com/rust-lang/crates.io-index" 519 | checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" 520 | dependencies = [ 521 | "cfg-if 1.0.0", 522 | ] 523 | 524 | [[package]] 525 | name = "derive_more" 526 | version = "0.99.17" 527 | source = "registry+https://github.com/rust-lang/crates.io-index" 528 | checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" 529 | dependencies = [ 530 | "convert_case", 531 | "proc-macro2", 532 | "quote", 533 | "rustc_version", 534 | "syn", 535 | ] 536 | 537 | [[package]] 538 | name = "diesel" 539 | version = "1.4.8" 540 | source = "registry+https://github.com/rust-lang/crates.io-index" 541 | checksum = "b28135ecf6b7d446b43e27e225622a038cc4e2930a1022f51cdb97ada19b8e4d" 542 | dependencies = [ 543 | "bitflags", 544 | "byteorder", 545 | "diesel_derives", 546 | "pq-sys", 547 | "r2d2", 548 | ] 549 | 550 | [[package]] 551 | name = "diesel_derives" 552 | version = "1.4.1" 553 | source = "registry+https://github.com/rust-lang/crates.io-index" 554 | checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3" 555 | dependencies = [ 556 | "proc-macro2", 557 | "quote", 558 | "syn", 559 | ] 560 | 561 | [[package]] 562 | name = "dotenv" 563 | version = "0.15.0" 564 | source = "registry+https://github.com/rust-lang/crates.io-index" 565 | checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" 566 | 567 | [[package]] 568 | name = "dtoa" 569 | version = "0.4.8" 570 | source = "registry+https://github.com/rust-lang/crates.io-index" 571 | checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" 572 | 573 | [[package]] 574 | name = "either" 575 | version = "1.8.0" 576 | source = "registry+https://github.com/rust-lang/crates.io-index" 577 | checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" 578 | 579 | [[package]] 580 | name = "encoding_rs" 581 | version = "0.8.31" 582 | source = "registry+https://github.com/rust-lang/crates.io-index" 583 | checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" 584 | dependencies = [ 585 | "cfg-if 1.0.0", 586 | ] 587 | 588 | [[package]] 589 | name = "enum-as-inner" 590 | version = "0.3.4" 591 | source = "registry+https://github.com/rust-lang/crates.io-index" 592 | checksum = "570d109b813e904becc80d8d5da38376818a143348413f7149f1340fe04754d4" 593 | dependencies = [ 594 | "heck", 595 | "proc-macro2", 596 | "quote", 597 | "syn", 598 | ] 599 | 600 | [[package]] 601 | name = "env_logger" 602 | version = "0.7.1" 603 | source = "registry+https://github.com/rust-lang/crates.io-index" 604 | checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" 605 | dependencies = [ 606 | "atty", 607 | "humantime", 608 | "log", 609 | "regex", 610 | "termcolor", 611 | ] 612 | 613 | [[package]] 614 | name = "failure" 615 | version = "0.1.8" 616 | source = "registry+https://github.com/rust-lang/crates.io-index" 617 | checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" 618 | dependencies = [ 619 | "backtrace", 620 | "failure_derive", 621 | ] 622 | 623 | [[package]] 624 | name = "failure_derive" 625 | version = "0.1.8" 626 | source = "registry+https://github.com/rust-lang/crates.io-index" 627 | checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" 628 | dependencies = [ 629 | "proc-macro2", 630 | "quote", 631 | "syn", 632 | "synstructure", 633 | ] 634 | 635 | [[package]] 636 | name = "flate2" 637 | version = "1.0.24" 638 | source = "registry+https://github.com/rust-lang/crates.io-index" 639 | checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" 640 | dependencies = [ 641 | "crc32fast", 642 | "miniz_oxide", 643 | ] 644 | 645 | [[package]] 646 | name = "fnv" 647 | version = "1.0.7" 648 | source = "registry+https://github.com/rust-lang/crates.io-index" 649 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 650 | 651 | [[package]] 652 | name = "form_urlencoded" 653 | version = "1.0.1" 654 | source = "registry+https://github.com/rust-lang/crates.io-index" 655 | checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" 656 | dependencies = [ 657 | "matches", 658 | "percent-encoding", 659 | ] 660 | 661 | [[package]] 662 | name = "fuchsia-zircon" 663 | version = "0.3.3" 664 | source = "registry+https://github.com/rust-lang/crates.io-index" 665 | checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" 666 | dependencies = [ 667 | "bitflags", 668 | "fuchsia-zircon-sys", 669 | ] 670 | 671 | [[package]] 672 | name = "fuchsia-zircon-sys" 673 | version = "0.3.3" 674 | source = "registry+https://github.com/rust-lang/crates.io-index" 675 | checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" 676 | 677 | [[package]] 678 | name = "futures" 679 | version = "0.3.24" 680 | source = "registry+https://github.com/rust-lang/crates.io-index" 681 | checksum = "7f21eda599937fba36daeb58a22e8f5cee2d14c4a17b5b7739c7c8e5e3b8230c" 682 | dependencies = [ 683 | "futures-channel", 684 | "futures-core", 685 | "futures-executor", 686 | "futures-io", 687 | "futures-sink", 688 | "futures-task", 689 | "futures-util", 690 | ] 691 | 692 | [[package]] 693 | name = "futures-channel" 694 | version = "0.3.24" 695 | source = "registry+https://github.com/rust-lang/crates.io-index" 696 | checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050" 697 | dependencies = [ 698 | "futures-core", 699 | "futures-sink", 700 | ] 701 | 702 | [[package]] 703 | name = "futures-core" 704 | version = "0.3.24" 705 | source = "registry+https://github.com/rust-lang/crates.io-index" 706 | checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf" 707 | 708 | [[package]] 709 | name = "futures-executor" 710 | version = "0.3.24" 711 | source = "registry+https://github.com/rust-lang/crates.io-index" 712 | checksum = "9ff63c23854bee61b6e9cd331d523909f238fc7636290b96826e9cfa5faa00ab" 713 | dependencies = [ 714 | "futures-core", 715 | "futures-task", 716 | "futures-util", 717 | ] 718 | 719 | [[package]] 720 | name = "futures-io" 721 | version = "0.3.24" 722 | source = "registry+https://github.com/rust-lang/crates.io-index" 723 | checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68" 724 | 725 | [[package]] 726 | name = "futures-macro" 727 | version = "0.3.24" 728 | source = "registry+https://github.com/rust-lang/crates.io-index" 729 | checksum = "42cd15d1c7456c04dbdf7e88bcd69760d74f3a798d6444e16974b505b0e62f17" 730 | dependencies = [ 731 | "proc-macro2", 732 | "quote", 733 | "syn", 734 | ] 735 | 736 | [[package]] 737 | name = "futures-sink" 738 | version = "0.3.24" 739 | source = "registry+https://github.com/rust-lang/crates.io-index" 740 | checksum = "21b20ba5a92e727ba30e72834706623d94ac93a725410b6a6b6fbc1b07f7ba56" 741 | 742 | [[package]] 743 | name = "futures-task" 744 | version = "0.3.24" 745 | source = "registry+https://github.com/rust-lang/crates.io-index" 746 | checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1" 747 | 748 | [[package]] 749 | name = "futures-util" 750 | version = "0.3.24" 751 | source = "registry+https://github.com/rust-lang/crates.io-index" 752 | checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90" 753 | dependencies = [ 754 | "futures-channel", 755 | "futures-core", 756 | "futures-io", 757 | "futures-macro", 758 | "futures-sink", 759 | "futures-task", 760 | "memchr", 761 | "pin-project-lite 0.2.9", 762 | "pin-utils", 763 | "slab", 764 | ] 765 | 766 | [[package]] 767 | name = "fxhash" 768 | version = "0.2.1" 769 | source = "registry+https://github.com/rust-lang/crates.io-index" 770 | checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" 771 | dependencies = [ 772 | "byteorder", 773 | ] 774 | 775 | [[package]] 776 | name = "getrandom" 777 | version = "0.1.16" 778 | source = "registry+https://github.com/rust-lang/crates.io-index" 779 | checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" 780 | dependencies = [ 781 | "cfg-if 1.0.0", 782 | "libc", 783 | "wasi 0.9.0+wasi-snapshot-preview1", 784 | ] 785 | 786 | [[package]] 787 | name = "gimli" 788 | version = "0.26.2" 789 | source = "registry+https://github.com/rust-lang/crates.io-index" 790 | checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" 791 | 792 | [[package]] 793 | name = "h2" 794 | version = "0.2.7" 795 | source = "registry+https://github.com/rust-lang/crates.io-index" 796 | checksum = "5e4728fd124914ad25e99e3d15a9361a879f6620f63cb56bbb08f95abb97a535" 797 | dependencies = [ 798 | "bytes 0.5.6", 799 | "fnv", 800 | "futures-core", 801 | "futures-sink", 802 | "futures-util", 803 | "http", 804 | "indexmap", 805 | "slab", 806 | "tokio", 807 | "tokio-util 0.3.1", 808 | "tracing", 809 | "tracing-futures", 810 | ] 811 | 812 | [[package]] 813 | name = "hashbrown" 814 | version = "0.12.3" 815 | source = "registry+https://github.com/rust-lang/crates.io-index" 816 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 817 | 818 | [[package]] 819 | name = "heck" 820 | version = "0.4.0" 821 | source = "registry+https://github.com/rust-lang/crates.io-index" 822 | checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" 823 | 824 | [[package]] 825 | name = "hermit-abi" 826 | version = "0.1.19" 827 | source = "registry+https://github.com/rust-lang/crates.io-index" 828 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 829 | dependencies = [ 830 | "libc", 831 | ] 832 | 833 | [[package]] 834 | name = "hostname" 835 | version = "0.3.1" 836 | source = "registry+https://github.com/rust-lang/crates.io-index" 837 | checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" 838 | dependencies = [ 839 | "libc", 840 | "match_cfg", 841 | "winapi 0.3.9", 842 | ] 843 | 844 | [[package]] 845 | name = "http" 846 | version = "0.2.8" 847 | source = "registry+https://github.com/rust-lang/crates.io-index" 848 | checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" 849 | dependencies = [ 850 | "bytes 1.2.1", 851 | "fnv", 852 | "itoa 1.0.3", 853 | ] 854 | 855 | [[package]] 856 | name = "httparse" 857 | version = "1.8.0" 858 | source = "registry+https://github.com/rust-lang/crates.io-index" 859 | checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" 860 | 861 | [[package]] 862 | name = "humantime" 863 | version = "1.3.0" 864 | source = "registry+https://github.com/rust-lang/crates.io-index" 865 | checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" 866 | dependencies = [ 867 | "quick-error", 868 | ] 869 | 870 | [[package]] 871 | name = "iana-time-zone" 872 | version = "0.1.47" 873 | source = "registry+https://github.com/rust-lang/crates.io-index" 874 | checksum = "4c495f162af0bf17656d0014a0eded5f3cd2f365fdd204548c2869db89359dc7" 875 | dependencies = [ 876 | "android_system_properties", 877 | "core-foundation-sys", 878 | "js-sys", 879 | "once_cell", 880 | "wasm-bindgen", 881 | "winapi 0.3.9", 882 | ] 883 | 884 | [[package]] 885 | name = "idna" 886 | version = "0.2.3" 887 | source = "registry+https://github.com/rust-lang/crates.io-index" 888 | checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" 889 | dependencies = [ 890 | "matches", 891 | "unicode-bidi", 892 | "unicode-normalization", 893 | ] 894 | 895 | [[package]] 896 | name = "indexmap" 897 | version = "1.9.1" 898 | source = "registry+https://github.com/rust-lang/crates.io-index" 899 | checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" 900 | dependencies = [ 901 | "autocfg", 902 | "hashbrown", 903 | "serde", 904 | ] 905 | 906 | [[package]] 907 | name = "instant" 908 | version = "0.1.12" 909 | source = "registry+https://github.com/rust-lang/crates.io-index" 910 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 911 | dependencies = [ 912 | "cfg-if 1.0.0", 913 | ] 914 | 915 | [[package]] 916 | name = "iovec" 917 | version = "0.1.4" 918 | source = "registry+https://github.com/rust-lang/crates.io-index" 919 | checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" 920 | dependencies = [ 921 | "libc", 922 | ] 923 | 924 | [[package]] 925 | name = "ipconfig" 926 | version = "0.2.2" 927 | source = "registry+https://github.com/rust-lang/crates.io-index" 928 | checksum = "f7e2f18aece9709094573a9f24f483c4f65caa4298e2f7ae1b71cc65d853fad7" 929 | dependencies = [ 930 | "socket2", 931 | "widestring", 932 | "winapi 0.3.9", 933 | "winreg", 934 | ] 935 | 936 | [[package]] 937 | name = "itoa" 938 | version = "0.4.8" 939 | source = "registry+https://github.com/rust-lang/crates.io-index" 940 | checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" 941 | 942 | [[package]] 943 | name = "itoa" 944 | version = "1.0.3" 945 | source = "registry+https://github.com/rust-lang/crates.io-index" 946 | checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" 947 | 948 | [[package]] 949 | name = "js-sys" 950 | version = "0.3.59" 951 | source = "registry+https://github.com/rust-lang/crates.io-index" 952 | checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" 953 | dependencies = [ 954 | "wasm-bindgen", 955 | ] 956 | 957 | [[package]] 958 | name = "juniper" 959 | version = "0.14.2" 960 | source = "registry+https://github.com/rust-lang/crates.io-index" 961 | checksum = "f662ba51e2fbc3d6dd1ca66be70b44963606a34473156abddcb0351fc6caa668" 962 | dependencies = [ 963 | "chrono", 964 | "fnv", 965 | "indexmap", 966 | "juniper_codegen", 967 | "serde", 968 | "serde_derive", 969 | "url", 970 | "uuid", 971 | ] 972 | 973 | [[package]] 974 | name = "juniper_codegen" 975 | version = "0.14.2" 976 | source = "registry+https://github.com/rust-lang/crates.io-index" 977 | checksum = "d40af234d8e971a9d7dda93ffbcc8a44a93f17e69e3067f72ce7a6894c41d51b" 978 | dependencies = [ 979 | "proc-macro2", 980 | "quote", 981 | "syn", 982 | ] 983 | 984 | [[package]] 985 | name = "kernel32-sys" 986 | version = "0.2.2" 987 | source = "registry+https://github.com/rust-lang/crates.io-index" 988 | checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" 989 | dependencies = [ 990 | "winapi 0.2.8", 991 | "winapi-build", 992 | ] 993 | 994 | [[package]] 995 | name = "language-tags" 996 | version = "0.2.2" 997 | source = "registry+https://github.com/rust-lang/crates.io-index" 998 | checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" 999 | 1000 | [[package]] 1001 | name = "lazy_static" 1002 | version = "1.4.0" 1003 | source = "registry+https://github.com/rust-lang/crates.io-index" 1004 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 1005 | 1006 | [[package]] 1007 | name = "libc" 1008 | version = "0.2.132" 1009 | source = "registry+https://github.com/rust-lang/crates.io-index" 1010 | checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" 1011 | 1012 | [[package]] 1013 | name = "linked-hash-map" 1014 | version = "0.5.6" 1015 | source = "registry+https://github.com/rust-lang/crates.io-index" 1016 | checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" 1017 | 1018 | [[package]] 1019 | name = "lock_api" 1020 | version = "0.4.8" 1021 | source = "registry+https://github.com/rust-lang/crates.io-index" 1022 | checksum = "9f80bf5aacaf25cbfc8210d1cfb718f2bf3b11c4c54e5afe36c236853a8ec390" 1023 | dependencies = [ 1024 | "autocfg", 1025 | "scopeguard", 1026 | ] 1027 | 1028 | [[package]] 1029 | name = "log" 1030 | version = "0.4.17" 1031 | source = "registry+https://github.com/rust-lang/crates.io-index" 1032 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" 1033 | dependencies = [ 1034 | "cfg-if 1.0.0", 1035 | ] 1036 | 1037 | [[package]] 1038 | name = "lru-cache" 1039 | version = "0.1.2" 1040 | source = "registry+https://github.com/rust-lang/crates.io-index" 1041 | checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" 1042 | dependencies = [ 1043 | "linked-hash-map", 1044 | ] 1045 | 1046 | [[package]] 1047 | name = "match_cfg" 1048 | version = "0.1.0" 1049 | source = "registry+https://github.com/rust-lang/crates.io-index" 1050 | checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" 1051 | 1052 | [[package]] 1053 | name = "matches" 1054 | version = "0.1.9" 1055 | source = "registry+https://github.com/rust-lang/crates.io-index" 1056 | checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" 1057 | 1058 | [[package]] 1059 | name = "memchr" 1060 | version = "2.5.0" 1061 | source = "registry+https://github.com/rust-lang/crates.io-index" 1062 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 1063 | 1064 | [[package]] 1065 | name = "mime" 1066 | version = "0.3.16" 1067 | source = "registry+https://github.com/rust-lang/crates.io-index" 1068 | checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" 1069 | 1070 | [[package]] 1071 | name = "miniz_oxide" 1072 | version = "0.5.4" 1073 | source = "registry+https://github.com/rust-lang/crates.io-index" 1074 | checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" 1075 | dependencies = [ 1076 | "adler", 1077 | ] 1078 | 1079 | [[package]] 1080 | name = "mio" 1081 | version = "0.6.23" 1082 | source = "registry+https://github.com/rust-lang/crates.io-index" 1083 | checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" 1084 | dependencies = [ 1085 | "cfg-if 0.1.10", 1086 | "fuchsia-zircon", 1087 | "fuchsia-zircon-sys", 1088 | "iovec", 1089 | "kernel32-sys", 1090 | "libc", 1091 | "log", 1092 | "miow", 1093 | "net2", 1094 | "slab", 1095 | "winapi 0.2.8", 1096 | ] 1097 | 1098 | [[package]] 1099 | name = "mio-uds" 1100 | version = "0.6.8" 1101 | source = "registry+https://github.com/rust-lang/crates.io-index" 1102 | checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" 1103 | dependencies = [ 1104 | "iovec", 1105 | "libc", 1106 | "mio", 1107 | ] 1108 | 1109 | [[package]] 1110 | name = "miow" 1111 | version = "0.2.2" 1112 | source = "registry+https://github.com/rust-lang/crates.io-index" 1113 | checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" 1114 | dependencies = [ 1115 | "kernel32-sys", 1116 | "net2", 1117 | "winapi 0.2.8", 1118 | "ws2_32-sys", 1119 | ] 1120 | 1121 | [[package]] 1122 | name = "net2" 1123 | version = "0.2.37" 1124 | source = "registry+https://github.com/rust-lang/crates.io-index" 1125 | checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" 1126 | dependencies = [ 1127 | "cfg-if 0.1.10", 1128 | "libc", 1129 | "winapi 0.3.9", 1130 | ] 1131 | 1132 | [[package]] 1133 | name = "num-integer" 1134 | version = "0.1.45" 1135 | source = "registry+https://github.com/rust-lang/crates.io-index" 1136 | checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" 1137 | dependencies = [ 1138 | "autocfg", 1139 | "num-traits", 1140 | ] 1141 | 1142 | [[package]] 1143 | name = "num-traits" 1144 | version = "0.2.15" 1145 | source = "registry+https://github.com/rust-lang/crates.io-index" 1146 | checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" 1147 | dependencies = [ 1148 | "autocfg", 1149 | ] 1150 | 1151 | [[package]] 1152 | name = "num_cpus" 1153 | version = "1.13.1" 1154 | source = "registry+https://github.com/rust-lang/crates.io-index" 1155 | checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" 1156 | dependencies = [ 1157 | "hermit-abi", 1158 | "libc", 1159 | ] 1160 | 1161 | [[package]] 1162 | name = "object" 1163 | version = "0.29.0" 1164 | source = "registry+https://github.com/rust-lang/crates.io-index" 1165 | checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" 1166 | dependencies = [ 1167 | "memchr", 1168 | ] 1169 | 1170 | [[package]] 1171 | name = "once_cell" 1172 | version = "1.14.0" 1173 | source = "registry+https://github.com/rust-lang/crates.io-index" 1174 | checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" 1175 | 1176 | [[package]] 1177 | name = "parking_lot" 1178 | version = "0.11.2" 1179 | source = "registry+https://github.com/rust-lang/crates.io-index" 1180 | checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" 1181 | dependencies = [ 1182 | "instant", 1183 | "lock_api", 1184 | "parking_lot_core 0.8.5", 1185 | ] 1186 | 1187 | [[package]] 1188 | name = "parking_lot" 1189 | version = "0.12.1" 1190 | source = "registry+https://github.com/rust-lang/crates.io-index" 1191 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" 1192 | dependencies = [ 1193 | "lock_api", 1194 | "parking_lot_core 0.9.3", 1195 | ] 1196 | 1197 | [[package]] 1198 | name = "parking_lot_core" 1199 | version = "0.8.5" 1200 | source = "registry+https://github.com/rust-lang/crates.io-index" 1201 | checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" 1202 | dependencies = [ 1203 | "cfg-if 1.0.0", 1204 | "instant", 1205 | "libc", 1206 | "redox_syscall", 1207 | "smallvec", 1208 | "winapi 0.3.9", 1209 | ] 1210 | 1211 | [[package]] 1212 | name = "parking_lot_core" 1213 | version = "0.9.3" 1214 | source = "registry+https://github.com/rust-lang/crates.io-index" 1215 | checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" 1216 | dependencies = [ 1217 | "cfg-if 1.0.0", 1218 | "libc", 1219 | "redox_syscall", 1220 | "smallvec", 1221 | "windows-sys", 1222 | ] 1223 | 1224 | [[package]] 1225 | name = "percent-encoding" 1226 | version = "2.1.0" 1227 | source = "registry+https://github.com/rust-lang/crates.io-index" 1228 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 1229 | 1230 | [[package]] 1231 | name = "pin-project" 1232 | version = "0.4.30" 1233 | source = "registry+https://github.com/rust-lang/crates.io-index" 1234 | checksum = "3ef0f924a5ee7ea9cbcea77529dba45f8a9ba9f622419fe3386ca581a3ae9d5a" 1235 | dependencies = [ 1236 | "pin-project-internal 0.4.30", 1237 | ] 1238 | 1239 | [[package]] 1240 | name = "pin-project" 1241 | version = "1.0.12" 1242 | source = "registry+https://github.com/rust-lang/crates.io-index" 1243 | checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" 1244 | dependencies = [ 1245 | "pin-project-internal 1.0.12", 1246 | ] 1247 | 1248 | [[package]] 1249 | name = "pin-project-internal" 1250 | version = "0.4.30" 1251 | source = "registry+https://github.com/rust-lang/crates.io-index" 1252 | checksum = "851c8d0ce9bebe43790dedfc86614c23494ac9f423dd618d3a61fc693eafe61e" 1253 | dependencies = [ 1254 | "proc-macro2", 1255 | "quote", 1256 | "syn", 1257 | ] 1258 | 1259 | [[package]] 1260 | name = "pin-project-internal" 1261 | version = "1.0.12" 1262 | source = "registry+https://github.com/rust-lang/crates.io-index" 1263 | checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" 1264 | dependencies = [ 1265 | "proc-macro2", 1266 | "quote", 1267 | "syn", 1268 | ] 1269 | 1270 | [[package]] 1271 | name = "pin-project-lite" 1272 | version = "0.1.12" 1273 | source = "registry+https://github.com/rust-lang/crates.io-index" 1274 | checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" 1275 | 1276 | [[package]] 1277 | name = "pin-project-lite" 1278 | version = "0.2.9" 1279 | source = "registry+https://github.com/rust-lang/crates.io-index" 1280 | checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" 1281 | 1282 | [[package]] 1283 | name = "pin-utils" 1284 | version = "0.1.0" 1285 | source = "registry+https://github.com/rust-lang/crates.io-index" 1286 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1287 | 1288 | [[package]] 1289 | name = "ppv-lite86" 1290 | version = "0.2.16" 1291 | source = "registry+https://github.com/rust-lang/crates.io-index" 1292 | checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" 1293 | 1294 | [[package]] 1295 | name = "pq-sys" 1296 | version = "0.4.7" 1297 | source = "registry+https://github.com/rust-lang/crates.io-index" 1298 | checksum = "3b845d6d8ec554f972a2c5298aad68953fd64e7441e846075450b44656a016d1" 1299 | dependencies = [ 1300 | "vcpkg", 1301 | ] 1302 | 1303 | [[package]] 1304 | name = "proc-macro2" 1305 | version = "1.0.43" 1306 | source = "registry+https://github.com/rust-lang/crates.io-index" 1307 | checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" 1308 | dependencies = [ 1309 | "unicode-ident", 1310 | ] 1311 | 1312 | [[package]] 1313 | name = "quick-error" 1314 | version = "1.2.3" 1315 | source = "registry+https://github.com/rust-lang/crates.io-index" 1316 | checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" 1317 | 1318 | [[package]] 1319 | name = "quote" 1320 | version = "1.0.21" 1321 | source = "registry+https://github.com/rust-lang/crates.io-index" 1322 | checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" 1323 | dependencies = [ 1324 | "proc-macro2", 1325 | ] 1326 | 1327 | [[package]] 1328 | name = "r2d2" 1329 | version = "0.8.10" 1330 | source = "registry+https://github.com/rust-lang/crates.io-index" 1331 | checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" 1332 | dependencies = [ 1333 | "log", 1334 | "parking_lot 0.12.1", 1335 | "scheduled-thread-pool", 1336 | ] 1337 | 1338 | [[package]] 1339 | name = "rand" 1340 | version = "0.7.3" 1341 | source = "registry+https://github.com/rust-lang/crates.io-index" 1342 | checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" 1343 | dependencies = [ 1344 | "getrandom", 1345 | "libc", 1346 | "rand_chacha", 1347 | "rand_core", 1348 | "rand_hc", 1349 | ] 1350 | 1351 | [[package]] 1352 | name = "rand_chacha" 1353 | version = "0.2.2" 1354 | source = "registry+https://github.com/rust-lang/crates.io-index" 1355 | checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" 1356 | dependencies = [ 1357 | "ppv-lite86", 1358 | "rand_core", 1359 | ] 1360 | 1361 | [[package]] 1362 | name = "rand_core" 1363 | version = "0.5.1" 1364 | source = "registry+https://github.com/rust-lang/crates.io-index" 1365 | checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 1366 | dependencies = [ 1367 | "getrandom", 1368 | ] 1369 | 1370 | [[package]] 1371 | name = "rand_hc" 1372 | version = "0.2.0" 1373 | source = "registry+https://github.com/rust-lang/crates.io-index" 1374 | checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" 1375 | dependencies = [ 1376 | "rand_core", 1377 | ] 1378 | 1379 | [[package]] 1380 | name = "redox_syscall" 1381 | version = "0.2.16" 1382 | source = "registry+https://github.com/rust-lang/crates.io-index" 1383 | checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" 1384 | dependencies = [ 1385 | "bitflags", 1386 | ] 1387 | 1388 | [[package]] 1389 | name = "regex" 1390 | version = "1.6.0" 1391 | source = "registry+https://github.com/rust-lang/crates.io-index" 1392 | checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" 1393 | dependencies = [ 1394 | "aho-corasick", 1395 | "memchr", 1396 | "regex-syntax", 1397 | ] 1398 | 1399 | [[package]] 1400 | name = "regex-syntax" 1401 | version = "0.6.27" 1402 | source = "registry+https://github.com/rust-lang/crates.io-index" 1403 | checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" 1404 | 1405 | [[package]] 1406 | name = "resolv-conf" 1407 | version = "0.6.3" 1408 | source = "registry+https://github.com/rust-lang/crates.io-index" 1409 | checksum = "11834e137f3b14e309437a8276714eed3a80d1ef894869e510f2c0c0b98b9f4a" 1410 | dependencies = [ 1411 | "hostname", 1412 | "quick-error", 1413 | ] 1414 | 1415 | [[package]] 1416 | name = "rustc-demangle" 1417 | version = "0.1.21" 1418 | source = "registry+https://github.com/rust-lang/crates.io-index" 1419 | checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" 1420 | 1421 | [[package]] 1422 | name = "rustc_version" 1423 | version = "0.4.0" 1424 | source = "registry+https://github.com/rust-lang/crates.io-index" 1425 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" 1426 | dependencies = [ 1427 | "semver", 1428 | ] 1429 | 1430 | [[package]] 1431 | name = "ryu" 1432 | version = "1.0.11" 1433 | source = "registry+https://github.com/rust-lang/crates.io-index" 1434 | checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" 1435 | 1436 | [[package]] 1437 | name = "scheduled-thread-pool" 1438 | version = "0.2.6" 1439 | source = "registry+https://github.com/rust-lang/crates.io-index" 1440 | checksum = "977a7519bff143a44f842fd07e80ad1329295bd71686457f18e496736f4bf9bf" 1441 | dependencies = [ 1442 | "parking_lot 0.12.1", 1443 | ] 1444 | 1445 | [[package]] 1446 | name = "scopeguard" 1447 | version = "1.1.0" 1448 | source = "registry+https://github.com/rust-lang/crates.io-index" 1449 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1450 | 1451 | [[package]] 1452 | name = "semver" 1453 | version = "1.0.13" 1454 | source = "registry+https://github.com/rust-lang/crates.io-index" 1455 | checksum = "93f6841e709003d68bb2deee8c343572bf446003ec20a583e76f7b15cebf3711" 1456 | 1457 | [[package]] 1458 | name = "serde" 1459 | version = "1.0.144" 1460 | source = "registry+https://github.com/rust-lang/crates.io-index" 1461 | checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860" 1462 | dependencies = [ 1463 | "serde_derive", 1464 | ] 1465 | 1466 | [[package]] 1467 | name = "serde_derive" 1468 | version = "1.0.144" 1469 | source = "registry+https://github.com/rust-lang/crates.io-index" 1470 | checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00" 1471 | dependencies = [ 1472 | "proc-macro2", 1473 | "quote", 1474 | "syn", 1475 | ] 1476 | 1477 | [[package]] 1478 | name = "serde_json" 1479 | version = "1.0.85" 1480 | source = "registry+https://github.com/rust-lang/crates.io-index" 1481 | checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" 1482 | dependencies = [ 1483 | "itoa 1.0.3", 1484 | "ryu", 1485 | "serde", 1486 | ] 1487 | 1488 | [[package]] 1489 | name = "serde_urlencoded" 1490 | version = "0.6.1" 1491 | source = "registry+https://github.com/rust-lang/crates.io-index" 1492 | checksum = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97" 1493 | dependencies = [ 1494 | "dtoa", 1495 | "itoa 0.4.8", 1496 | "serde", 1497 | "url", 1498 | ] 1499 | 1500 | [[package]] 1501 | name = "sha1" 1502 | version = "0.6.1" 1503 | source = "registry+https://github.com/rust-lang/crates.io-index" 1504 | checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" 1505 | dependencies = [ 1506 | "sha1_smol", 1507 | ] 1508 | 1509 | [[package]] 1510 | name = "sha1_smol" 1511 | version = "1.0.0" 1512 | source = "registry+https://github.com/rust-lang/crates.io-index" 1513 | checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" 1514 | 1515 | [[package]] 1516 | name = "signal-hook-registry" 1517 | version = "1.4.0" 1518 | source = "registry+https://github.com/rust-lang/crates.io-index" 1519 | checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" 1520 | dependencies = [ 1521 | "libc", 1522 | ] 1523 | 1524 | [[package]] 1525 | name = "slab" 1526 | version = "0.4.7" 1527 | source = "registry+https://github.com/rust-lang/crates.io-index" 1528 | checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" 1529 | dependencies = [ 1530 | "autocfg", 1531 | ] 1532 | 1533 | [[package]] 1534 | name = "smallvec" 1535 | version = "1.9.0" 1536 | source = "registry+https://github.com/rust-lang/crates.io-index" 1537 | checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" 1538 | 1539 | [[package]] 1540 | name = "socket2" 1541 | version = "0.3.19" 1542 | source = "registry+https://github.com/rust-lang/crates.io-index" 1543 | checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" 1544 | dependencies = [ 1545 | "cfg-if 1.0.0", 1546 | "libc", 1547 | "winapi 0.3.9", 1548 | ] 1549 | 1550 | [[package]] 1551 | name = "syn" 1552 | version = "1.0.99" 1553 | source = "registry+https://github.com/rust-lang/crates.io-index" 1554 | checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" 1555 | dependencies = [ 1556 | "proc-macro2", 1557 | "quote", 1558 | "unicode-ident", 1559 | ] 1560 | 1561 | [[package]] 1562 | name = "synstructure" 1563 | version = "0.12.6" 1564 | source = "registry+https://github.com/rust-lang/crates.io-index" 1565 | checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" 1566 | dependencies = [ 1567 | "proc-macro2", 1568 | "quote", 1569 | "syn", 1570 | "unicode-xid", 1571 | ] 1572 | 1573 | [[package]] 1574 | name = "termcolor" 1575 | version = "1.1.3" 1576 | source = "registry+https://github.com/rust-lang/crates.io-index" 1577 | checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" 1578 | dependencies = [ 1579 | "winapi-util", 1580 | ] 1581 | 1582 | [[package]] 1583 | name = "threadpool" 1584 | version = "1.8.1" 1585 | source = "registry+https://github.com/rust-lang/crates.io-index" 1586 | checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" 1587 | dependencies = [ 1588 | "num_cpus", 1589 | ] 1590 | 1591 | [[package]] 1592 | name = "time" 1593 | version = "0.1.44" 1594 | source = "registry+https://github.com/rust-lang/crates.io-index" 1595 | checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" 1596 | dependencies = [ 1597 | "libc", 1598 | "wasi 0.10.0+wasi-snapshot-preview1", 1599 | "winapi 0.3.9", 1600 | ] 1601 | 1602 | [[package]] 1603 | name = "tinyvec" 1604 | version = "1.6.0" 1605 | source = "registry+https://github.com/rust-lang/crates.io-index" 1606 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 1607 | dependencies = [ 1608 | "tinyvec_macros", 1609 | ] 1610 | 1611 | [[package]] 1612 | name = "tinyvec_macros" 1613 | version = "0.1.0" 1614 | source = "registry+https://github.com/rust-lang/crates.io-index" 1615 | checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" 1616 | 1617 | [[package]] 1618 | name = "todos" 1619 | version = "0.1.0" 1620 | dependencies = [ 1621 | "actix-rt", 1622 | "actix-web", 1623 | "diesel", 1624 | "dotenv", 1625 | "env_logger", 1626 | "juniper", 1627 | "r2d2", 1628 | "serde_json", 1629 | ] 1630 | 1631 | [[package]] 1632 | name = "tokio" 1633 | version = "0.2.25" 1634 | source = "registry+https://github.com/rust-lang/crates.io-index" 1635 | checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092" 1636 | dependencies = [ 1637 | "bytes 0.5.6", 1638 | "futures-core", 1639 | "iovec", 1640 | "lazy_static", 1641 | "libc", 1642 | "memchr", 1643 | "mio", 1644 | "mio-uds", 1645 | "pin-project-lite 0.1.12", 1646 | "signal-hook-registry", 1647 | "slab", 1648 | "winapi 0.3.9", 1649 | ] 1650 | 1651 | [[package]] 1652 | name = "tokio-util" 1653 | version = "0.2.0" 1654 | source = "registry+https://github.com/rust-lang/crates.io-index" 1655 | checksum = "571da51182ec208780505a32528fc5512a8fe1443ab960b3f2f3ef093cd16930" 1656 | dependencies = [ 1657 | "bytes 0.5.6", 1658 | "futures-core", 1659 | "futures-sink", 1660 | "log", 1661 | "pin-project-lite 0.1.12", 1662 | "tokio", 1663 | ] 1664 | 1665 | [[package]] 1666 | name = "tokio-util" 1667 | version = "0.3.1" 1668 | source = "registry+https://github.com/rust-lang/crates.io-index" 1669 | checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" 1670 | dependencies = [ 1671 | "bytes 0.5.6", 1672 | "futures-core", 1673 | "futures-sink", 1674 | "log", 1675 | "pin-project-lite 0.1.12", 1676 | "tokio", 1677 | ] 1678 | 1679 | [[package]] 1680 | name = "tracing" 1681 | version = "0.1.36" 1682 | source = "registry+https://github.com/rust-lang/crates.io-index" 1683 | checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" 1684 | dependencies = [ 1685 | "cfg-if 1.0.0", 1686 | "log", 1687 | "pin-project-lite 0.2.9", 1688 | "tracing-core", 1689 | ] 1690 | 1691 | [[package]] 1692 | name = "tracing-core" 1693 | version = "0.1.29" 1694 | source = "registry+https://github.com/rust-lang/crates.io-index" 1695 | checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" 1696 | dependencies = [ 1697 | "once_cell", 1698 | ] 1699 | 1700 | [[package]] 1701 | name = "tracing-futures" 1702 | version = "0.2.5" 1703 | source = "registry+https://github.com/rust-lang/crates.io-index" 1704 | checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" 1705 | dependencies = [ 1706 | "pin-project 1.0.12", 1707 | "tracing", 1708 | ] 1709 | 1710 | [[package]] 1711 | name = "trust-dns-proto" 1712 | version = "0.18.0-alpha.2" 1713 | source = "registry+https://github.com/rust-lang/crates.io-index" 1714 | checksum = "2a7f3a2ab8a919f5eca52a468866a67ed7d3efa265d48a652a9a3452272b413f" 1715 | dependencies = [ 1716 | "async-trait", 1717 | "enum-as-inner", 1718 | "failure", 1719 | "futures", 1720 | "idna", 1721 | "lazy_static", 1722 | "log", 1723 | "rand", 1724 | "smallvec", 1725 | "socket2", 1726 | "tokio", 1727 | "url", 1728 | ] 1729 | 1730 | [[package]] 1731 | name = "trust-dns-resolver" 1732 | version = "0.18.0-alpha.2" 1733 | source = "registry+https://github.com/rust-lang/crates.io-index" 1734 | checksum = "6f90b1502b226f8b2514c6d5b37bafa8c200d7ca4102d57dc36ee0f3b7a04a2f" 1735 | dependencies = [ 1736 | "cfg-if 0.1.10", 1737 | "failure", 1738 | "futures", 1739 | "ipconfig", 1740 | "lazy_static", 1741 | "log", 1742 | "lru-cache", 1743 | "resolv-conf", 1744 | "smallvec", 1745 | "tokio", 1746 | "trust-dns-proto", 1747 | ] 1748 | 1749 | [[package]] 1750 | name = "unicode-bidi" 1751 | version = "0.3.8" 1752 | source = "registry+https://github.com/rust-lang/crates.io-index" 1753 | checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" 1754 | 1755 | [[package]] 1756 | name = "unicode-ident" 1757 | version = "1.0.3" 1758 | source = "registry+https://github.com/rust-lang/crates.io-index" 1759 | checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" 1760 | 1761 | [[package]] 1762 | name = "unicode-normalization" 1763 | version = "0.1.21" 1764 | source = "registry+https://github.com/rust-lang/crates.io-index" 1765 | checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" 1766 | dependencies = [ 1767 | "tinyvec", 1768 | ] 1769 | 1770 | [[package]] 1771 | name = "unicode-xid" 1772 | version = "0.2.3" 1773 | source = "registry+https://github.com/rust-lang/crates.io-index" 1774 | checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" 1775 | 1776 | [[package]] 1777 | name = "url" 1778 | version = "2.2.2" 1779 | source = "registry+https://github.com/rust-lang/crates.io-index" 1780 | checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" 1781 | dependencies = [ 1782 | "form_urlencoded", 1783 | "idna", 1784 | "matches", 1785 | "percent-encoding", 1786 | ] 1787 | 1788 | [[package]] 1789 | name = "uuid" 1790 | version = "0.7.4" 1791 | source = "registry+https://github.com/rust-lang/crates.io-index" 1792 | checksum = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" 1793 | 1794 | [[package]] 1795 | name = "vcpkg" 1796 | version = "0.2.15" 1797 | source = "registry+https://github.com/rust-lang/crates.io-index" 1798 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 1799 | 1800 | [[package]] 1801 | name = "wasi" 1802 | version = "0.9.0+wasi-snapshot-preview1" 1803 | source = "registry+https://github.com/rust-lang/crates.io-index" 1804 | checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" 1805 | 1806 | [[package]] 1807 | name = "wasi" 1808 | version = "0.10.0+wasi-snapshot-preview1" 1809 | source = "registry+https://github.com/rust-lang/crates.io-index" 1810 | checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" 1811 | 1812 | [[package]] 1813 | name = "wasm-bindgen" 1814 | version = "0.2.82" 1815 | source = "registry+https://github.com/rust-lang/crates.io-index" 1816 | checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" 1817 | dependencies = [ 1818 | "cfg-if 1.0.0", 1819 | "wasm-bindgen-macro", 1820 | ] 1821 | 1822 | [[package]] 1823 | name = "wasm-bindgen-backend" 1824 | version = "0.2.82" 1825 | source = "registry+https://github.com/rust-lang/crates.io-index" 1826 | checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" 1827 | dependencies = [ 1828 | "bumpalo", 1829 | "log", 1830 | "once_cell", 1831 | "proc-macro2", 1832 | "quote", 1833 | "syn", 1834 | "wasm-bindgen-shared", 1835 | ] 1836 | 1837 | [[package]] 1838 | name = "wasm-bindgen-macro" 1839 | version = "0.2.82" 1840 | source = "registry+https://github.com/rust-lang/crates.io-index" 1841 | checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" 1842 | dependencies = [ 1843 | "quote", 1844 | "wasm-bindgen-macro-support", 1845 | ] 1846 | 1847 | [[package]] 1848 | name = "wasm-bindgen-macro-support" 1849 | version = "0.2.82" 1850 | source = "registry+https://github.com/rust-lang/crates.io-index" 1851 | checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" 1852 | dependencies = [ 1853 | "proc-macro2", 1854 | "quote", 1855 | "syn", 1856 | "wasm-bindgen-backend", 1857 | "wasm-bindgen-shared", 1858 | ] 1859 | 1860 | [[package]] 1861 | name = "wasm-bindgen-shared" 1862 | version = "0.2.82" 1863 | source = "registry+https://github.com/rust-lang/crates.io-index" 1864 | checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" 1865 | 1866 | [[package]] 1867 | name = "widestring" 1868 | version = "0.4.3" 1869 | source = "registry+https://github.com/rust-lang/crates.io-index" 1870 | checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c" 1871 | 1872 | [[package]] 1873 | name = "winapi" 1874 | version = "0.2.8" 1875 | source = "registry+https://github.com/rust-lang/crates.io-index" 1876 | checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" 1877 | 1878 | [[package]] 1879 | name = "winapi" 1880 | version = "0.3.9" 1881 | source = "registry+https://github.com/rust-lang/crates.io-index" 1882 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1883 | dependencies = [ 1884 | "winapi-i686-pc-windows-gnu", 1885 | "winapi-x86_64-pc-windows-gnu", 1886 | ] 1887 | 1888 | [[package]] 1889 | name = "winapi-build" 1890 | version = "0.1.1" 1891 | source = "registry+https://github.com/rust-lang/crates.io-index" 1892 | checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" 1893 | 1894 | [[package]] 1895 | name = "winapi-i686-pc-windows-gnu" 1896 | version = "0.4.0" 1897 | source = "registry+https://github.com/rust-lang/crates.io-index" 1898 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1899 | 1900 | [[package]] 1901 | name = "winapi-util" 1902 | version = "0.1.5" 1903 | source = "registry+https://github.com/rust-lang/crates.io-index" 1904 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1905 | dependencies = [ 1906 | "winapi 0.3.9", 1907 | ] 1908 | 1909 | [[package]] 1910 | name = "winapi-x86_64-pc-windows-gnu" 1911 | version = "0.4.0" 1912 | source = "registry+https://github.com/rust-lang/crates.io-index" 1913 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1914 | 1915 | [[package]] 1916 | name = "windows-sys" 1917 | version = "0.36.1" 1918 | source = "registry+https://github.com/rust-lang/crates.io-index" 1919 | checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" 1920 | dependencies = [ 1921 | "windows_aarch64_msvc", 1922 | "windows_i686_gnu", 1923 | "windows_i686_msvc", 1924 | "windows_x86_64_gnu", 1925 | "windows_x86_64_msvc", 1926 | ] 1927 | 1928 | [[package]] 1929 | name = "windows_aarch64_msvc" 1930 | version = "0.36.1" 1931 | source = "registry+https://github.com/rust-lang/crates.io-index" 1932 | checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" 1933 | 1934 | [[package]] 1935 | name = "windows_i686_gnu" 1936 | version = "0.36.1" 1937 | source = "registry+https://github.com/rust-lang/crates.io-index" 1938 | checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" 1939 | 1940 | [[package]] 1941 | name = "windows_i686_msvc" 1942 | version = "0.36.1" 1943 | source = "registry+https://github.com/rust-lang/crates.io-index" 1944 | checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" 1945 | 1946 | [[package]] 1947 | name = "windows_x86_64_gnu" 1948 | version = "0.36.1" 1949 | source = "registry+https://github.com/rust-lang/crates.io-index" 1950 | checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" 1951 | 1952 | [[package]] 1953 | name = "windows_x86_64_msvc" 1954 | version = "0.36.1" 1955 | source = "registry+https://github.com/rust-lang/crates.io-index" 1956 | checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" 1957 | 1958 | [[package]] 1959 | name = "winreg" 1960 | version = "0.6.2" 1961 | source = "registry+https://github.com/rust-lang/crates.io-index" 1962 | checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" 1963 | dependencies = [ 1964 | "winapi 0.3.9", 1965 | ] 1966 | 1967 | [[package]] 1968 | name = "ws2_32-sys" 1969 | version = "0.2.1" 1970 | source = "registry+https://github.com/rust-lang/crates.io-index" 1971 | checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" 1972 | dependencies = [ 1973 | "winapi 0.2.8", 1974 | "winapi-build", 1975 | ] 1976 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "todos" 3 | version = "0.1.0" 4 | authors = ["lucperkins "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | actix-rt = "1.0.0" 9 | actix-web = "2.0.0" 10 | diesel = { version = "1.4.3", features = ["postgres", "r2d2"] } 11 | dotenv = "0.15.0" 12 | env_logger = "0.7.1" 13 | juniper = "0.14.2" 14 | r2d2 = "0.8.8" 15 | serde_json = "1.0.44" 16 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CARGO = cargo 2 | 3 | build: 4 | $(CARGO) build 5 | 6 | check: 7 | $(CARGO) check 8 | 9 | fmt: 10 | $(CARGO) fmt 11 | 12 | open: 13 | open http://localhost:4000/graphql 14 | 15 | release: 16 | $(CARGO) build --release 17 | 18 | run: 19 | $(CARGO) run 20 | 21 | db-up: 22 | docker compose up 23 | 24 | db-down: 25 | docker compose down 26 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | release: ./target/release/diesel migration run 2 | web: ./target/release/todos 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rust + GraphQL + Juniper + Diesel + Postgres + Actix 2 | 3 | Yes, I know that this is a borderline absurd web stack for the ubiquitous TODO application but I had a *lot* of trouble getting this all to work. I started using these things for a more ambitious project and I'd love to spare you the trouble. So here's some basic boilerplate to get you up and running. 4 | 5 | ## Components 6 | 7 | Here's what does what: 8 | 9 | Component | Tool/lib 10 | :---------|:-------- 11 | Web server | [actix-web](https://github.com/actix/actix-web) 12 | Database | [PostgreSQL](https://postgresql.org) 13 | SQL engine | [Diesel](https://diesel.rs) 14 | GraphQL library | [Juniper](https://github.com/graphql-rust/juniper) 15 | GraphQL UI | [GraphQL Playground](https://github.com/prisma-labs/graphql-playground) 16 | 17 | ## Run locally 18 | 19 | > Before you get started, make sure that you have [PostgreSQL](https://postgresql.org), [Rust](https://rust-lang.org), [Cargo](https://doc.rust-lang.org/cargo/), and the [Diesel](https://diesel.rs) CLI installed and that you have Postgres running somewhere. 20 | 21 | ```bash 22 | # Fetch the repo 23 | git clone https://github.com/lucperkins/rust-actix-diesel-postgres-juniper 24 | cd rust-actix-diesel-postgres-juniper 25 | 26 | # If you would like to run the postgres server in docker 27 | docker compose up 28 | 29 | # Set up the database 30 | cp .env.example .env # Modify this file to match your Postgres installation 31 | 32 | diesel setup 33 | diesel migration run 34 | 35 | cargo run # could take a while! 36 | ``` 37 | 38 | > The `DATABASE_URL` can be any Postgres installation. For my purposes, I have it set to `postgres://localhost:5432/todos`. 39 | 40 | Once the server is running, you can access the GraphQL Playground UI at http://localhost:4000/graphql. 41 | 42 | ## Schema 43 | 44 | The server implements the following GraphQL schema: 45 | 46 | ```graphql 47 | type Todo { 48 | id: ID! 49 | task: String! 50 | done: Boolean! 51 | } 52 | 53 | input CreateTodoInput { 54 | task: String! 55 | done: Boolean 56 | } 57 | 58 | type Query { 59 | allTodos: [Todo!]! 60 | getTodoById(id: Int): Todo 61 | } 62 | 63 | type Mutation { 64 | createTodo(input: CreateTodoInput): Todo 65 | markTodoAsDone(id: Int): Todo 66 | markTodoAsNotDone(id: Int): Todo 67 | } 68 | 69 | schema { 70 | Query 71 | Mutation 72 | } 73 | ``` 74 | 75 | ## Tour of the codebase 76 | 77 | File | What it provides 78 | :----|:---------------- 79 | [`context.rs`](./src/context.rs) | The GraphQL [context](https://graphql.org/learn/execution) that handles query execution 80 | [`data.rs`](./src/data.rs) | A `Todos` struct and some helper functions encapsulate the [Diesel](https://diesel.rs)-powered Postgres querying logic 81 | [`db.rs`](./src/db.rs) | The connection pool that handles the Postgres connection 82 | [`endpoints.rs`](./src/endpoints.rs) | The `/graphql` HTTP endpoint that makes GraphQL and the GraphQL Playground work 83 | [`graphql.rs`](./src/graphql.rs) | The `Query`, `Mutation`, and `Schema` objects that undergird the GraphQL interface 84 | [`lib.rs`](./src/lib.rs) | Just the standard `lib.rs` 85 | [`main.rs`](./src/main.rs) | [Actix](https://actix.rs) HTTP server setup 86 | [`models.rs`](./src/models.rs) | All of the data types used for querying Postgres and providing GraphQL results 87 | [`schema.rs`](./src/schema.rs) | The Diesel-generated table schema 88 | 89 | ## Future TODOs 90 | 91 | Get it? Anyway, here's some areas for improvement (pull requests very much welcome): 92 | 93 | * **Error handling** — Right now errors basically propagate directly from Diesel/Postgres into the GraphQL JSON output, which is subpar. If any of you can point me to good educational resources on this, please file an issue! 94 | * **Better execution engine** — The server uses the extremely powerful [actix-web](https://github.com/actix/actix-web) but the actual DB interactions don't use Actix actors and it'd take this setup to the next level if they did. 95 | * **Use macros for schema generation** — The powerful [`juniper_from_schema`](https://docs.rs/juniper-from-schema/0.5.1/juniper_from_schema/) macro could help reduce boilerplate and improve development velocity. 96 | 97 | ## Acknowledgments 98 | 99 | I'm basically a beginner with Rust and would not have been able to put this together without peeking long and hard at the example projects and blog posts listed below. The lower-level bits you see here are basically stolen from [BrendanBall](https://github.com/BrendanBall). All that I've added is the [`Todos`](./src/data.rs) data construct for executing queries. 100 | 101 | ### Example projects 102 | 103 | * [BrendanBall/example-actix-web-juniper-diesel](https://github.com/BrendanBall/example-actix-web-juniper-diesel) 104 | * [iwilsonq/rust-graphql-example](https://github.com/iwilsonq/rust-graphql-example) 105 | * [dancespiele/listing_people_api_actix](https://github.com/dancespiele/listing_people_api_actix) 106 | 107 | ### Blog posts 108 | 109 | * [Building Powerful GraphQL Servers with Rust](https://dev.to/open-graphql/building-powerful-graphql-servers-with-rust-3gla) 110 | * [[Rust] juniper + diesel + actix-webでGraphQLしてみる](https://qiita.com/yagince/items/e378bbaa95e08bab7467) 111 | -------------------------------------------------------------------------------- /api/todos.graphql: -------------------------------------------------------------------------------- 1 | type Todo { 2 | id: ID! 3 | task: String! 4 | done: Boolean! 5 | } 6 | 7 | input CreateTodoInput { 8 | task: String! 9 | done: Boolean 10 | } 11 | 12 | type Query { 13 | allTodos: [Todo!]! 14 | getTodoById(id: Int): Todo 15 | } 16 | 17 | type Mutation { 18 | createTodo(input: CreateTodoInput): Todo! 19 | markTodoAsDone(id: Int): Todo! 20 | markTodoAsNotDone(id: Int): Todo! 21 | } 22 | 23 | schema { 24 | Query 25 | Mutation 26 | } 27 | -------------------------------------------------------------------------------- /diesel.toml: -------------------------------------------------------------------------------- 1 | [print_schema] 2 | file = "src/schema.rs" 3 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | 3 | db: 4 | image: postgres:latest 5 | restart: always 6 | environment: 7 | POSTGRES_DB: todos 8 | POSTGRES_USER: user 9 | POSTGRES_PASSWORD: example 10 | ports: 11 | - "5432:5432" 12 | volumes: 13 | - pgdata:/var/lib/postgresql/data 14 | 15 | volumes: 16 | pgdata: 17 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-utils": { 4 | "inputs": { 5 | "systems": "systems" 6 | }, 7 | "locked": { 8 | "lastModified": 1710146030, 9 | "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", 10 | "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", 11 | "revCount": 92, 12 | "type": "tarball", 13 | "url": "https://api.flakehub.com/f/pinned/numtide/flake-utils/0.1.92%2Brev-b1d9ab70662946ef0850d488da1c9019f3a9752a/018e2ca5-e5a2-7f80-9261-445a8cecd4d7/source.tar.gz" 14 | }, 15 | "original": { 16 | "type": "tarball", 17 | "url": "https://flakehub.com/f/numtide/flake-utils/0.1.%2A.tar.gz" 18 | } 19 | }, 20 | "nixpkgs": { 21 | "locked": { 22 | "lastModified": 1721409541, 23 | "narHash": "sha256-b6PLr0Ty7JPDBtJtjnYzlBf02bbH9alWMAgispMkTwk=", 24 | "rev": "0c53b6b8c2a3e46c68e04417e247bba660689c9d", 25 | "revCount": 633273, 26 | "type": "tarball", 27 | "url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.2405.633273%2Brev-0c53b6b8c2a3e46c68e04417e247bba660689c9d/0190d12a-ecb2-7cba-b494-d1e5145f6b10/source.tar.gz" 28 | }, 29 | "original": { 30 | "type": "tarball", 31 | "url": "https://flakehub.com/f/NixOS/nixpkgs/0.2405.%2A.tar.gz" 32 | } 33 | }, 34 | "nixpkgs_2": { 35 | "locked": { 36 | "lastModified": 1718428119, 37 | "narHash": "sha256-WdWDpNaq6u1IPtxtYHHWpl5BmabtpmLnMAx0RdJ/vo8=", 38 | "owner": "NixOS", 39 | "repo": "nixpkgs", 40 | "rev": "e6cea36f83499eb4e9cd184c8a8e823296b50ad5", 41 | "type": "github" 42 | }, 43 | "original": { 44 | "owner": "NixOS", 45 | "ref": "nixpkgs-unstable", 46 | "repo": "nixpkgs", 47 | "type": "github" 48 | } 49 | }, 50 | "root": { 51 | "inputs": { 52 | "flake-utils": "flake-utils", 53 | "nixpkgs": "nixpkgs", 54 | "rust-overlay": "rust-overlay" 55 | } 56 | }, 57 | "rust-overlay": { 58 | "inputs": { 59 | "nixpkgs": "nixpkgs_2" 60 | }, 61 | "locked": { 62 | "lastModified": 1721441897, 63 | "narHash": "sha256-gYGX9/22tPNeF7dR6bWN5rsrpU4d06GnQNNgZ6ZiXz0=", 64 | "rev": "b7996075da11a2d441cfbf4e77c2939ce51506fd", 65 | "revCount": 1462, 66 | "type": "tarball", 67 | "url": "https://api.flakehub.com/f/pinned/oxalica/rust-overlay/0.1.1462%2Brev-b7996075da11a2d441cfbf4e77c2939ce51506fd/0190cdf1-bc22-7e18-b7b9-7b140f0f5b3f/source.tar.gz" 68 | }, 69 | "original": { 70 | "type": "tarball", 71 | "url": "https://flakehub.com/f/oxalica/rust-overlay/0.1.%2A.tar.gz" 72 | } 73 | }, 74 | "systems": { 75 | "locked": { 76 | "lastModified": 1681028828, 77 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 78 | "owner": "nix-systems", 79 | "repo": "default", 80 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 81 | "type": "github" 82 | }, 83 | "original": { 84 | "owner": "nix-systems", 85 | "repo": "default", 86 | "type": "github" 87 | } 88 | } 89 | }, 90 | "root": "root", 91 | "version": 7 92 | } 93 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "A Nix-flake-based Rust development environment"; 3 | 4 | inputs = { 5 | flake-utils.url = "https://flakehub.com/f/numtide/flake-utils/0.1.*.tar.gz"; 6 | nixpkgs.url = "https://flakehub.com/f/NixOS/nixpkgs/0.2405.*.tar.gz"; 7 | rust-overlay.url = "https://flakehub.com/f/oxalica/rust-overlay/0.1.*.tar.gz"; 8 | }; 9 | 10 | outputs = 11 | { self 12 | , flake-utils 13 | , nixpkgs 14 | , rust-overlay 15 | }: 16 | 17 | flake-utils.lib.eachDefaultSystem (system: 18 | let 19 | overlays = [ 20 | rust-overlay.overlays.default 21 | (final: prev: { 22 | rustToolchain = final.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; 23 | }) 24 | ]; 25 | 26 | pkgs = import nixpkgs { inherit system overlays; }; 27 | in 28 | { 29 | devShell = pkgs.mkShell { 30 | packages = with pkgs; [ 31 | rustToolchain 32 | cargo-deny 33 | cargo-edit 34 | bacon 35 | diesel-cli 36 | postgresql 37 | ]; 38 | }; 39 | }); 40 | } 41 | -------------------------------------------------------------------------------- /migrations/00000000000000_diesel_initial_setup/down.sql: -------------------------------------------------------------------------------- 1 | -- This file was automatically created by Diesel to setup helper functions 2 | -- and other internal bookkeeping. This file is safe to edit, any future 3 | -- changes will be added to existing projects as new migrations. 4 | 5 | DROP FUNCTION IF EXISTS diesel_manage_updated_at(_tbl regclass); 6 | DROP FUNCTION IF EXISTS diesel_set_updated_at(); 7 | -------------------------------------------------------------------------------- /migrations/00000000000000_diesel_initial_setup/up.sql: -------------------------------------------------------------------------------- 1 | -- This file was automatically created by Diesel to setup helper functions 2 | -- and other internal bookkeeping. This file is safe to edit, any future 3 | -- changes will be added to existing projects as new migrations. 4 | 5 | 6 | 7 | 8 | -- Sets up a trigger for the given table to automatically set a column called 9 | -- `updated_at` whenever the row is modified (unless `updated_at` was included 10 | -- in the modified columns) 11 | -- 12 | -- # Example 13 | -- 14 | -- ```sql 15 | -- CREATE TABLE users (id SERIAL PRIMARY KEY, updated_at TIMESTAMP NOT NULL DEFAULT NOW()); 16 | -- 17 | -- SELECT diesel_manage_updated_at('users'); 18 | -- ``` 19 | CREATE OR REPLACE FUNCTION diesel_manage_updated_at(_tbl regclass) RETURNS VOID AS $$ 20 | BEGIN 21 | EXECUTE format('CREATE TRIGGER set_updated_at BEFORE UPDATE ON %s 22 | FOR EACH ROW EXECUTE PROCEDURE diesel_set_updated_at()', _tbl); 23 | END; 24 | $$ LANGUAGE plpgsql; 25 | 26 | CREATE OR REPLACE FUNCTION diesel_set_updated_at() RETURNS trigger AS $$ 27 | BEGIN 28 | IF ( 29 | NEW IS DISTINCT FROM OLD AND 30 | NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at 31 | ) THEN 32 | NEW.updated_at := current_timestamp; 33 | END IF; 34 | RETURN NEW; 35 | END; 36 | $$ LANGUAGE plpgsql; 37 | -------------------------------------------------------------------------------- /migrations/2019-12-27-225611_create_todos/down.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE todos 2 | -------------------------------------------------------------------------------- /migrations/2019-12-27-225611_create_todos/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE todos ( 2 | id SERIAL PRIMARY KEY, 3 | task VARCHAR NOT NULL, 4 | done BOOLEAN NOT NULL DEFAULT 'f' 5 | ) 6 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "1.78.0" 3 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | edition = "2018" 2 | indent_style = "Block" 3 | max_width = 89 4 | reorder_imports = true 5 | -------------------------------------------------------------------------------- /src/context.rs: -------------------------------------------------------------------------------- 1 | use super::db::PostgresPool; 2 | 3 | // The GraphQL context, which needs to provide everything necessary for 4 | // interacting with the database. 5 | pub struct GraphQLContext { 6 | pub pool: PostgresPool, 7 | } 8 | 9 | // This impl allows us to pass in GraphQLContext as the Context for GraphQL 10 | // objects 11 | impl juniper::Context for GraphQLContext {} 12 | -------------------------------------------------------------------------------- /src/data.rs: -------------------------------------------------------------------------------- 1 | use super::models::{CreateTodoInput, NewTodo, Todo}; 2 | use super::schema::todos::dsl::*; 3 | use diesel::pg::PgConnection; 4 | use diesel::prelude::*; 5 | use juniper::{graphql_value, FieldError, FieldResult}; 6 | 7 | const DEFAULT_TODO_DONE: bool = false; 8 | 9 | // This struct is basically a query manager. All the methods that it 10 | // provides are static, making it a convenient abstraction for interacting 11 | // with the database. 12 | pub struct Todos; 13 | 14 | // Note that all the function names here map directly onto the function names 15 | // associated with the Query and Mutation structs. This is NOT necessary but 16 | // I personally prefer it. 17 | impl Todos { 18 | pub fn all_todos(conn: &PgConnection) -> FieldResult> { 19 | let res = todos.load::(conn); 20 | 21 | graphql_translate(res) 22 | } 23 | 24 | pub fn create_todo( 25 | conn: &PgConnection, 26 | new_todo: CreateTodoInput, 27 | ) -> FieldResult { 28 | use super::schema::todos; 29 | 30 | let new_todo = NewTodo { 31 | task: &new_todo.task, 32 | done: &new_todo.done.unwrap_or(DEFAULT_TODO_DONE), // Default value is false 33 | }; 34 | 35 | let res = diesel::insert_into(todos::table) 36 | .values(&new_todo) 37 | .get_result(conn); 38 | 39 | graphql_translate(res) 40 | } 41 | 42 | pub fn get_todo_by_id( 43 | conn: &PgConnection, 44 | todo_id: i32, 45 | ) -> FieldResult> { 46 | match todos.find(todo_id).get_result::(conn) { 47 | Ok(todo) => Ok(Some(todo)), 48 | Err(e) => match e { 49 | // Without this translation, GraphQL will return an error rather 50 | // than the more semantically sound JSON null if no TODO is found. 51 | diesel::result::Error::NotFound => FieldResult::Ok(None), 52 | _ => FieldResult::Err(FieldError::from(e)), 53 | }, 54 | } 55 | } 56 | 57 | pub fn done_todos(conn: &PgConnection) -> FieldResult> { 58 | let res = todos.filter(done.eq(true)).load::(conn); 59 | 60 | graphql_translate(res) 61 | } 62 | 63 | pub fn not_done_todos(conn: &PgConnection) -> FieldResult> { 64 | let res = todos.filter(done.eq(false)).load::(conn); 65 | 66 | graphql_translate(res) 67 | } 68 | 69 | pub fn mark_todo_as_done(conn: &PgConnection, todo_id: i32) -> FieldResult { 70 | mark_todo_as(conn, todo_id, true) 71 | } 72 | 73 | pub fn mark_todo_as_not_done( 74 | conn: &PgConnection, 75 | todo_id: i32, 76 | ) -> FieldResult { 77 | mark_todo_as(conn, todo_id, false) 78 | } 79 | } 80 | 81 | fn graphql_translate(res: Result) -> FieldResult { 82 | match res { 83 | Ok(t) => Ok(t), 84 | Err(e) => FieldResult::Err(FieldError::from(e)), 85 | } 86 | } 87 | 88 | // This helper function ensures that users don't mark TODOs as done that are already done 89 | // (or not done that are already not done). 90 | fn mark_todo_as(conn: &PgConnection, todo_id: i32, is_done: bool) -> FieldResult { 91 | let res = todos.find(todo_id).get_result::(conn); 92 | 93 | // Poor man's Ternary operator for error output text 94 | let msg = if is_done { "done" } else { "not done" }; 95 | 96 | match res { 97 | Ok(todo) => { 98 | if todo.done == is_done { 99 | let err = FieldError::new( 100 | format!("TODO already marked as {}", msg), 101 | // TODO: better error output 102 | graphql_value!({ "cannot_update": "confict"}), 103 | ); 104 | FieldResult::Err(err) 105 | } else { 106 | let res = diesel::update(todos.find(todo_id)) 107 | .set(done.eq(is_done)) 108 | .get_result::(conn); 109 | graphql_translate(res) 110 | } 111 | } 112 | Err(e) => FieldResult::Err(FieldError::from(e)), 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/db.rs: -------------------------------------------------------------------------------- 1 | use diesel::pg::PgConnection; 2 | use diesel::r2d2::ConnectionManager; 3 | use dotenv::dotenv; 4 | use r2d2::Pool; 5 | use std::env; 6 | 7 | // The Postgres-specific connection pool managing all database connections. 8 | pub type PostgresPool = Pool>; 9 | 10 | pub fn get_pool() -> PostgresPool { 11 | // TODO: pass the connection URL into this function rather than extracting 12 | // it from the environment within this function 13 | dotenv().ok(); 14 | let url = env::var("DATABASE_URL").expect("no DB URL"); // TODO: handle errors 15 | let mgr = ConnectionManager::::new(url); 16 | r2d2::Pool::builder() 17 | .build(mgr) 18 | .expect("could not build connection pool") // TODO: handle errors 19 | } 20 | -------------------------------------------------------------------------------- /src/endpoints.rs: -------------------------------------------------------------------------------- 1 | use super::context::GraphQLContext; 2 | use super::db::PostgresPool; 3 | use super::graphql::create_schema; 4 | use super::graphql::Schema; 5 | use actix_web::{web, Error, HttpResponse}; 6 | use juniper::http::playground::playground_source; 7 | use juniper::http::GraphQLRequest; 8 | use std::sync::Arc; 9 | 10 | // The configuration callback that enables us to add the /graphql route 11 | // to the actix-web server. 12 | pub fn graphql_endpoints(config: &mut web::ServiceConfig) { 13 | let schema = Arc::new(create_schema()); 14 | config 15 | .data(schema) 16 | .route("/graphql", web::post().to(graphql)) 17 | .route("/graphql", web::get().to(graphql_playground)); 18 | } 19 | 20 | // The GraphQL Playground route. 21 | async fn graphql_playground() -> HttpResponse { 22 | HttpResponse::Ok() 23 | .content_type("text/html; charset=utf-8") 24 | .body(playground_source("/graphql")) 25 | } 26 | 27 | // The core handler that provides all GraphQL functionality. 28 | async fn graphql( 29 | // The DB connection pool 30 | pool: web::Data, 31 | // The GraphQL schema 32 | schema: web::Data>, 33 | // The incoming HTTP request 34 | data: web::Json, 35 | ) -> Result { 36 | // Instantiate a context 37 | let ctx = GraphQLContext { 38 | pool: pool.get_ref().to_owned(), 39 | }; 40 | 41 | // Handle the incoming request and return a string result (or error) 42 | let res = web::block(move || { 43 | let res = data.execute(&schema, &ctx); 44 | Ok::<_, serde_json::error::Error>(serde_json::to_string(&res)?) 45 | }) 46 | .await 47 | .map_err(Error::from)?; 48 | 49 | // Return the string as a JSON payload 50 | Ok(HttpResponse::Ok() 51 | .content_type("application/json") 52 | .body(res)) 53 | } 54 | -------------------------------------------------------------------------------- /src/graphql.rs: -------------------------------------------------------------------------------- 1 | use super::context::GraphQLContext; 2 | use diesel::pg::PgConnection; 3 | use juniper::{FieldResult, RootNode}; 4 | 5 | use super::data::Todos; 6 | use super::models::{CreateTodoInput, Todo}; 7 | 8 | // The root GraphQL query 9 | pub struct Query; 10 | 11 | // The root Query struct relies on GraphQLContext to provide the connection pool 12 | // needed to execute actual Postgres queries. 13 | #[juniper::object(Context = GraphQLContext)] 14 | impl Query { 15 | // This annotation isn't really necessary, as Juniper would convert the 16 | // all_todos function name into CamelCase. But I like to keep it explicit. 17 | #[graphql(name = "allTodos")] 18 | pub fn all_todos(context: &GraphQLContext) -> FieldResult> { 19 | // TODO: pass the GraphQLContext into the querying functions rather 20 | // than a PgConnection (for brevity's sake) 21 | let conn: &PgConnection = &context.pool.get().unwrap(); 22 | 23 | Todos::all_todos(conn) 24 | } 25 | 26 | #[graphql(name = "doneTodos")] 27 | pub fn done_todos(context: &GraphQLContext) -> FieldResult> { 28 | let conn: &PgConnection = &context.pool.get().unwrap(); 29 | 30 | Todos::done_todos(conn) 31 | } 32 | 33 | #[graphql(name = "notDoneTodos")] 34 | pub fn done_todos(context: &GraphQLContext) -> FieldResult> { 35 | let conn: &PgConnection = &context.pool.get().unwrap(); 36 | 37 | Todos::not_done_todos(conn) 38 | } 39 | 40 | #[graphql(name = "getTodoById")] 41 | pub fn get_todo_by_id( 42 | context: &GraphQLContext, 43 | id: i32, 44 | ) -> FieldResult> { 45 | let conn: &PgConnection = &context.pool.get().unwrap(); 46 | 47 | Todos::get_todo_by_id(conn, id) 48 | } 49 | } 50 | 51 | // The root GraphQL mutation 52 | pub struct Mutation; 53 | 54 | #[juniper::object(Context = GraphQLContext)] 55 | impl Mutation { 56 | #[graphql(name = "createTodo")] 57 | pub fn create_todo( 58 | context: &GraphQLContext, 59 | input: CreateTodoInput, 60 | ) -> FieldResult { 61 | let conn: &PgConnection = &context.pool.get().unwrap(); 62 | 63 | Todos::create_todo(conn, input) 64 | } 65 | 66 | #[graphql(name = "markTodoAsDone")] 67 | pub fn mark_todo_as_done(context: &GraphQLContext, id: i32) -> FieldResult { 68 | let conn: &PgConnection = &context.pool.get().unwrap(); 69 | 70 | Todos::mark_todo_as_done(conn, id) 71 | } 72 | 73 | #[graphql(name = "markTodoAsNotDone")] 74 | pub fn mark_todo_as_not_done( 75 | context: &GraphQLContext, 76 | id: i32, 77 | ) -> FieldResult { 78 | let conn: &PgConnection = &context.pool.get().unwrap(); 79 | 80 | Todos::mark_todo_as_not_done(conn, id) 81 | } 82 | } 83 | 84 | // And finally the root schema that pulls the query and mutation together. Perhaps someday 85 | // you'll see a Subscription struct here as well. 86 | pub type Schema = RootNode<'static, Query, Mutation>; 87 | 88 | pub fn create_schema() -> Schema { 89 | Schema::new(Query, Mutation) 90 | } 91 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate diesel; 3 | 4 | pub mod context; 5 | pub mod data; 6 | pub mod db; 7 | pub mod endpoints; 8 | pub mod graphql; 9 | pub mod models; 10 | pub mod schema; 11 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate actix_rt; 2 | extern crate actix_web; 3 | extern crate diesel; 4 | extern crate dotenv; 5 | extern crate env_logger; 6 | extern crate juniper; 7 | extern crate r2d2; 8 | extern crate todos; 9 | 10 | use std::{env, io}; 11 | 12 | use actix_web::{middleware, App, HttpServer}; 13 | 14 | use todos::db::get_pool; 15 | use todos::endpoints::graphql_endpoints; 16 | 17 | #[actix_rt::main] 18 | async fn main() -> io::Result<()> { 19 | logging_setup(); 20 | 21 | // Instantiate a new connection pool 22 | let pool = get_pool(); 23 | 24 | // Start up the server, passing in (a) the connection pool 25 | // to make it available to all endpoints and (b) the configuration 26 | // function that adds the /graphql logic. 27 | HttpServer::new(move || { 28 | App::new() 29 | .data(pool.clone()) 30 | .wrap(middleware::Logger::default()) 31 | .configure(graphql_endpoints) 32 | }) 33 | .bind("127.0.0.1:4000")? 34 | .run() 35 | .await 36 | } 37 | 38 | // TODO: more fine-grained logging setup 39 | fn logging_setup() { 40 | env::set_var("RUST_LOG", "actix_web=info"); 41 | env_logger::init(); 42 | } 43 | -------------------------------------------------------------------------------- /src/models.rs: -------------------------------------------------------------------------------- 1 | use super::schema::todos; 2 | use juniper::GraphQLInputObject; 3 | 4 | // The core data type undergirding the GraphQL interface 5 | #[derive(Queryable)] 6 | pub struct Todo { 7 | pub id: i32, 8 | pub task: String, 9 | pub done: bool, 10 | } 11 | 12 | // I've chosen to make the fields explicit, but could've gotten the same result 13 | // applying #[derive(juniper::GraphQLObject)] to the Todo struct above 14 | #[juniper::object] 15 | impl Todo { 16 | #[graphql(name = "id")] 17 | fn id(&self) -> i32 { 18 | self.id 19 | } 20 | 21 | #[graphql(name = "task")] 22 | pub fn task(&self) -> &str { 23 | self.task.as_str() 24 | } 25 | 26 | #[graphql(name = "done")] 27 | fn done(&self) -> bool { 28 | self.done 29 | } 30 | } 31 | 32 | // Used to create new TODOs 33 | #[derive(Insertable)] 34 | #[table_name = "todos"] 35 | pub struct NewTodo<'a> { 36 | pub task: &'a str, 37 | pub done: &'a bool, 38 | } 39 | 40 | // The GraphQL input object for creating TODOs 41 | #[derive(GraphQLInputObject)] 42 | pub struct CreateTodoInput { 43 | pub task: String, 44 | pub done: Option, 45 | } 46 | -------------------------------------------------------------------------------- /src/schema.rs: -------------------------------------------------------------------------------- 1 | // @generated automatically by Diesel CLI. 2 | 3 | diesel::table! { 4 | todos (id) { 5 | id -> Int4, 6 | task -> Varchar, 7 | done -> Bool, 8 | } 9 | } 10 | --------------------------------------------------------------------------------