포트폴리오 - 데이터베이스 연결 1

갤럭시4414·2022년 11월 5일
0

러스트에서 PostgreSQL 을 연결하기 위한 모듈? crate?을 찾아봤는데 이 녀석만 나온다. 읽다 보니 그냥 postgres 와 tokio-postgres 가 있는데, tokio 가 붙은 녀석은 asynchronous를 지원한다고 한다. 비동기가 왠지 좋아 보여서 살펴 보았으나 tokio 는 뭔가 더 심오한 느낌이라 일단 synchronous 버전인 postgres 로 일단 해봐야겠다.

간단하게 테스트를 위한 데이터베이스와 테이블을 만들었다.

postgres=# create database portfolio_test;
CREATE DATABASE
postgres=# \c portfolio_test
You are now connected to database "portfolio_test" as user "postgres".
portfolio_test=# CREATE TABLE tb_user (
portfolio_test(#     id SERIAL PRIMARY KEY,
portfolio_test(#     name VARCHAR(64)
portfolio_test(# );
CREATE TABLE

backend 프로젝트의 Cargo.toml 파일에 postgres 도 추가 해 주자.

backend/Cargo.toml

...

[dependencies]
rocket = "0.5.0-rc.2"
postgres = "0.19.4"

이번에도 main.rs 에 샘플 코드를 붙여 넣자.

backend/main.rs

extern crate postgres;

use postgres::{Client, NoTls};

fn test_db() {
    let mut client = Client::connect("host=localhost user=postgres password=hello!1234 database=portfolio_test", NoTls)?;
    
    for row in client.query("SELECT id, name FROM user", &[])? {
        let id: i32 = row.get(0);
        let name: &str = row.get(1);
    
        println!("found user: {} {}", id, name);
    }
}

#[get("/")]
fn index() -> &'static str {
    test_db();

    return "Hello, world!"
}

그리고 cargo run 을 했는데...
에라가 난다

error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
  --> backend/src/main.rs:7:120
   |
6  | / fn test_db() {
7  | |     let mut client = Client::connect("host=localhost user=postgres password=hello!1234 dbname=portfolio_test", NoTls)?;
   | |                                                                                                                        ^ cannot use the `?` operator in a function that returns `()`

무언가 ? 에 신비한 기능이 있나보다.
공식 문서를 살펴보니 Rust 는 리턴값에 결과와 오류를 선택해서 전달할 수 있는 type 인 Result 가 있는데, 오류가 있는 경우 오류를 리턴하고 없는 경우 result 를 취하는 기능인가보다.

뭔가 좀 알흠다운 방법을 찾고 싶지만, 간단하게 이렇게 처치 했다.

backend/main.rs

extern crate postgres;

use postgres::{Client, NoTls};
use std::option::{Option};

fn test_db() -> Option<postgres::Error> {
    let mut client = Client::connect("host=localhost user=postgres password=hello!1234 database=portfolio_test", NoTls).ok()?;
    
    for row in client.query("SELECT id, name FROM user", &[]).ok()? {
  • Option<postgres::Error> 을 리턴하도록 했다.
  • ? 연산자가 Result<T, E> 인 경우 Result<T, E> 를 리턴하기 때문에 Option<> 로 바꿀 수 있도록 ok() 를 붙였다.

ok 를 붙이는 건 rust 컴파일러가 알려주었는데 똑똑한 것 같다.

error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option`
  --> backend/src/main.rs:8:120
   |
7  | / fn test_db() -> Option<postgres::Error> {
8  | |     let mut client = Client::connect("host=localhost user=postgres password=hello!1234 database=portfolio_test", NoTls)?;
   | |                                                                                                                        ^ use `.ok()?` if you want to discard the `Result<Infallible, postgres::Error>` error information

다시 실행 해 보자!
는 에라가 났다.

thread 'rocket-worker-thread' panicked at 'Cannot start a runtime from within a runtime. This happens because a function (like `block_on`) attempted to block the current thread while the thread is being used to drive asynchronous tasks.', /Users/galaxy/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.21.2/src/runtime/scheduler/current_thread.rs:516:26

_-_ rocket 이 기본으로 비동기인가보다 + postgres 가 동기라고 해놓고 내부적으로 비동기를 쓰나보다. 갑자기 피곤해진다. 내일 이어서 하자.

profile
풀스택개발자를꿈꾸는

0개의 댓글