Firebase SQL Connect를 사용하면 Google Cloud SQL로 관리되는 PostgreSQL 인스턴스의 커넥터를 만들 수 있습니다. 이러한 커넥터는 스키마의 데이터를 사용하는 쿼리 및 변형의 조합입니다.
시작하기 가이드에서는 PostgreSQL용 영화 리뷰 앱 스키마를 소개했습니다.
이 가이드에서는 변형을 비롯한 배포 가능한 관리 작업과 임시 관리 작업도 소개했습니다.
- 배포 가능한 변형 은 정의한 API 엔드포인트가 있는 커넥터의 클라이언트 앱에서 호출하기 위해 구현하는 변형입니다. SQL Connect는 인증 및 승인을 이러한 변형에 통합하고 API를 기반으로 클라이언트 SDK를 생성합니다.
- 임시 관리 변형 은 권한이 있는 환경에서 실행되어 테이블을 채우고 관리합니다. Firebase 콘솔에서, Firebase Admin SDK을 사용하는 권한이 있는 환경에서, SQL Connect VS Code 확장 프로그램을 사용하는 로컬 개발 환경에서 이러한 변형을 만들고 실행할 수 있습니다.
이 가이드에서는 배포 가능한 변형 을 자세히 살펴봅니다.
변형의 기능SQL Connect
SQL Connect를 사용하면 PostgreSQL 데이터베이스가 제공되는 모든 예상되는 방식으로 기본 변형을 실행할 수 있습니다.
- CRUD 작업 실행
- 트랜잭션으로 다단계 작업 관리
하지만 SQL Connect의 GraphQL 확장 프로그램을 사용하면 더 빠르고 효율적인 앱을 위한 고급 변형을 구현할 수 있습니다.
- 많은 작업에서 반환되는 키 스칼라 를 사용하여 레코드에 대한 반복 작업을 간소화합니다.
- 서버 값 을 사용하여 서버에서 제공하는 작업으로 데이터를 채웁니다.
- 다단계 변형 작업 과정에서 쿼리를 실행하여 데이터를 조회하고 코드 줄과 서버로의 왕복을 저장합니다.
생성된 필드를 사용하여 변형 구현
SQL Connect 작업은 스키마의 유형 및 유형 관계를 기반으로 SQL Connect에서 자동으로 생성하는 필드 집합 을 확장합니다. 이러한 필드는 스키마를 수정할 때마다 로컬 도구에서 생성됩니다.
생성된 필드를 사용하여 단일 테이블의 개별 레코드 생성, 업데이트, 삭제부터 더 복잡한 다중 테이블 업데이트까지 변형을 구현할 수 있습니다.스키마에 Movie 유형과 연결된 Actor 유형이 있다고 가정합니다.
SQL Connect는 movie_insert,
movie_update, movie_delete 필드를 생성합니다.
movie_insert 필드를 사용한 변형
|
|
이 필드를 사용하여 단일 영화를 만듭니다. mutation CreateMovie($data: Movie_Data!) { movie_insert(data: $data) { key } } |
movie_update 필드를 사용한 변형
|
|
이 필드를 사용하여 키별로 단일 영화를 업데이트합니다. mutation UpdateMovie($myKey: Movie_Key!, $data: Movie_Data!) { movie_update(key: $myKey, data: $data) { key } } |
movie_delete 필드를 사용한 변형
|
|
이 필드를 사용하여 키별로 단일 영화를 삭제합니다. mutation DeleteMovie($myKey: Movie_Key!) { movie_delete(key: $myKey) { key } } |
변형의 필수 요소
SQL Connect 변형은 SQL Connect 확장 프로그램이 있는 GraphQL 변형입니다. 일반 GraphQL 변형과 마찬가지로 작업 이름과 GraphQL 변수 목록을 정의할 수 있습니다.
SQL Connect는 지시어와 같은 맞춤설정된 GraphQL 쿼리를
@auth 및 @transaction로 확장합니다.
따라서 다음 변형에는 다음이 포함됩니다.
mutation유형 정의SignUp작업 (변형) 이름- 단일 변수
$username작업 인수 - 단일 지시어
@auth - 단일 필드
user_insert.
mutation SignUp($username: String!) @auth(level: USER) {
user_insert(data: {
id_expr: "auth.uid"
username: $username
})
}
모든 변형 인수에는 유형 선언, String과 같은 기본 제공 유형 또는 Movie와 같은 스키마 정의 맞춤 유형이 필요합니다.
기본 변형 작성
변형 작성을 시작하여 데이터베이스에서 개별 레코드를 만들고 업데이트하고 삭제할 수 있습니다.
만들기
기본 만들기를 실행해 보겠습니다.
# Create a movie based on user input
mutation CreateMovie($title: String!, $releaseYear: Int!, $genre: String!, $rating: Int!) {
movie_insert(data: {
title: $title
releaseYear: $releaseYear
genre: $genre
rating: $rating
})
}
# Create a movie with default values
mutation CreateMovie2 {
movie_insert(data: {
title: "Sherlock Holmes"
releaseYear: 2009
genre: "Mystery"
rating: 5
})
}
또는 upsert를 실행해 보겠습니다.
# Movie upsert using combination of variables and literals
mutation UpsertMovie($title: String!) {
movie_upsert(data: {
title: $title
releaseYear: 2009
genre: "Mystery"
rating: 5
genre: "Mystery/Thriller"
})
}
업데이트 실행
업데이트는 다음과 같습니다. 제작자와 감독은 이러한 평균 평점이 추세에 맞기를 바랍니다.
movie_update 필드에는 레코드를 식별하는 예상되는 id 인수와 이 업데이트에서 값을 설정하는 데 사용할 수 있는 data 필드가 포함되어 있습니다.
mutation UpdateMovie(
$id: UUID!,
$genre: String!,
$rating: Int!,
$description: String!
) {
movie_update(id: $id,
data: {
genre: $genre
rating: $rating
description: $description
})
}
여러 업데이트를 실행하려면 movie_updateMany 필드를 사용합니다.
# Multiple updates (increase all ratings of a genre)
mutation IncreaseRatingForGenre($genre: String!, $rating: Int!) {
movie_updateMany(
where: { genre: { eq: $genre } },
data:
{
rating: $rating
})
}
_update로 증가, 감소, 추가, 삽입 작업 사용
_update 및 _updateMany 변형에서
data:의 값을 명시적으로 설정할 수 있지만 증가와 같은 연산자를 적용하여
값을 업데이트하는 것이 더 합리적인 경우가 많습니다.
이전 업데이트 예시를 수정하려면 특정 영화의 평점을 높이려고 한다고 가정합니다. inc 연산자와 함께 rating_update 문법을 사용할 수 있습니다.
mutation UpdateMovie(
$id: UUID!,
$ratingIncrement: Int!
) {
movie_update(id: $id, data: {
rating_update: {
inc: $ratingIncrement
}
})
}
SQL Connect는 필드 업데이트를 위해 다음 연산자를 지원합니다.
inc:Int,Int64,Float,Date,Timestamp데이터 유형을 증가시킵니다.dec는Int,Int64,Float,Date,Timestamp데이터 유형을 감소시킵니다.
목록의 경우 다음을 사용하여 개별 값 또는 값 목록으로 업데이트할 수도 있습니다.
add: 벡터 목록을 제외한 목록 유형에 항목이 아직 없는 경우 항목을 추가합니다.remove: 벡터 목록을 제외한 목록 유형에서 항목이 있는 경우 모든 항목을 삭제합니다.append: 벡터 목록을 제외한 목록 유형에 항목을 추가합니다.prepend: 벡터 목록을 제외한 목록 유형에 항목을 삽입합니다.
삭제 실행
물론 영화 데이터를 삭제할 수 있습니다. 영화 보존론자들은 물리적 영화가 최대한 오랫동안 유지되기를 바랄 것입니다.
# Delete by key
mutation DeleteMovie($id: UUID!) {
movie_delete(id: $id)
}
여기서 _deleteMany를 사용할 수 있습니다.
# Multiple deletes
mutation DeleteUnpopularMovies($minRating: Int!) {
movie_deleteMany(where: { rating: { le: $minRating } })
}
관계에 변형 작성
관계에서 암시적 _upsert 변형을 사용하는 방법을 살펴보세요.
# Create or update a one to one relation
mutation MovieMetadataUpsert($movieId: UUID!, $director: String!) {
movieMetadata_upsert(
data: { movie: { id: $movieId }, director: $director }
)
}
효율적인 변형을 위한 스키마 설계
SQL Connect는 더 효율적인 변형을 작성하고 왕복 작업을 저장할 수 있는 두 가지 중요한 기능을 제공합니다.
키 스칼라는 스키마의 키 필드에서 SQL Connect 자동으로 어셈블하는 간결한 객체 식별자입니다. 키 스칼라는 효율성에 관한 것으로, 단일 호출에서 데이터의 ID와 구조에 관한 정보를 찾을 수 있습니다. 특히 새 레코드에 순차적 작업을 실행하고 향후 작업에 전달할 고유 식별자가 필요한 경우, 더 복잡한 작업을 실행하기 위해 관계형 키에 액세스하려는 경우에 유용합니다.
서버 값을 사용하면 저장된 값 또는 쉽게 계산할 수 있는 값을 사용하여 서버에서 테이블의 필드를 동적으로 채울 수 있습니다.
인수의 특정 서버 측 CEL 표현식에 따라expr 예를 들어 작업 요청에 저장된 시간을 사용하여 필드에 액세스할 때 타임스탬프가 적용된 필드를 정의할 수 있습니다(updatedAt: Timestamp!
@default(expr: "request.time")).
고급 변형 작성: SQL Connect 문법을 사용하여 값 제공field_expr
키 스칼라 및 서버 값에서 설명한 대로 서버가 클라이언트 요청에 응답하여 id 및 날짜와 같은 일반 필드의 값을 채우도록 스키마를 설계할 수 있습니다.
또한 클라이언트 앱의
SQL Connect request 객체에서 전송된 사용자 ID와 같은 데이터를 사용할 수 있습니다.
변형을 구현할 때는 field_expr 문법을 사용하여 서버에서 생성된 업데이트를 트리거하거나 요청에서 데이터에 액세스합니다. 예를 들어 요청에 저장된 승인 uid를 _upsert 작업에 전달하려면 "auth.uid"를 userId_expr 필드에 전달합니다.
# Add a movie to the user's favorites list
mutation AddFavoritedMovie($movieId: UUID!) @auth(level: USER) {
favorite_movie_upsert(data: { userId_expr: "auth.uid", movieId: $movieId })
}
# Remove a movie from the user's favorites list
mutation DeleteFavoritedMovie($movieId: UUID!) @auth(level: USER) {
favorite_movie_delete(key: { userId_expr: "auth.uid", movieId: $movieId })
}
또는 익숙한 할 일 목록 앱에서 새 할 일 목록을 만들 때 id_expr을 전달하여 서버에 목록의 UUID를 자동 생성하도록 지시할 수 있습니다.
mutation CreateTodoListWithFirstItem(
$listName: String!
) @transaction {
# Step 1
todoList_insert(data: {
id_expr: "uuidV4()", # <-- auto-generated. Or a column-level @default on `type TodoList` will also work
name: $listName,
})
}
자세한 내용은 _Expr 스칼라 참조의
스칼라를 참고하세요.
고급 변형 작성: 다단계 작업
하나의 변형에 여러 쓰기 필드 (예: 삽입)를 포함하려는 경우가 많습니다. 또한 변형을 실행하는 동안 데이터베이스를 읽어 삽입 또는 업데이트를 실행하기 전에 기존 데이터를 조회하고 확인할 수도 있습니다. 이러한 옵션을 사용하면 왕복 작업과 비용을 절약할 수 있습니다.
SQL Connect를 사용하면 다음을 지원하여 변형에서 다단계 로직을 실행할 수 있습니다.
여러 쓰기 필드
변형의 여러 읽기 필드 (
query필드 키워드 사용)관계형 데이터베이스에서 익숙한 트랜잭션 지원을 제공하는
@transaction지시어, which provides transaction supportCEL 표현식을 사용하여 읽기의 콘텐츠를 평가하고 이러한 평가 결과를 기반으로 다음을 실행할 수 있는
@check지시어- 변형에서 정의한 생성, 업데이트, 삭제를 진행합니다.
- 쿼리 필드의 결과를 반환합니다.
- 반환된 메시지를 사용하여 클라이언트 코드에서 적절한 로직을 실행합니다.
와이어 프로토콜 결과에서 쿼리 필드 결과를 생략할 수 있는
@redact지시어복잡한 다단계 작업에서 실행된 모든 변형 및 쿼리의 누적 결과를 저장하는 CEL
response결합response결합에 액세스할 수 있습니다.expr:인수를 통해@check지시어에서- 서버 값으로
field_expr문법을 사용하여
@transaction 지시어
다단계 변형 지원에는 트랜잭션을 사용한 오류 처리가 포함됩니다.
@transaction 지시어는 단일 쓰기 필드 (예: _insert 또는 _update) 또는 여러 쓰기 필드가 있는 변형이 항상 데이터베이스 트랜잭션에서 실행되도록 합니다.
@transaction이 없는 변형은 각 루트 필드를 순서대로 하나씩 실행합니다. 이 작업은 후속 실행의 영향이 아니라 오류를 부분 필드 오류로 표시합니다.@transaction이 있는 변형은 완전히 성공하거나 완전히 실패합니다. 트랜잭션 내의 필드 중 하나라도 실패하면 전체 트랜잭션이 롤백됩니다.
@check 및 @redact 지시어
@check 지시어는 지정된 필드가 쿼리 결과에 있는지 확인합니다. CEL (Common Expression Language) 표현식은 필드 값을 테스트하는 데 사용됩니다. 지시어의 기본 동작은 값이 null 또는 [] (빈 목록)인 노드를 확인하고 거부하는 것입니다.
@redact 지시어는 클라이언트의 응답 일부를 수정합니다. 수정된 필드는 데이터 변경 및 @check를 비롯한 부작용에 대해 계속 평가되며 결과는 CEL 표현식의 후속 단계에서 계속 사용할 수 있습니다.
@check, @check(message:), @redact 사용
@check 및 @redact의 주요 용도는 논리의 조회를 사용하여 특정 작업을 승인해야 하는지 결정하는 것이지만 클라이언트에는 숨기는 것입니다. 쿼리는 클라이언트 코드에서 올바르게 처리하는 데 유용한 메시지를 반환할 수 있습니다.
query GetMovieEditors($movieId: UUID!) @auth(level: USER) {
moviePermission(key: { movieId: $movieId, userId_expr: "auth.uid" }) @redact {
role @check(expr: "this == 'admin'", message: "You must be an admin to view all editors of a movie.")
}
moviePermissions(where: { movieId: { eq: $movieId }, role: { eq: "editor" } }) {
user {
id
username
}
}
}
승인 확인의 @check 및 @redact 지시어에 관해 자세히 알아보려면
승인 데이터 조회에 관한 설명을 참고하세요.
@check를 사용하여 키 검증
_update와 같은 일부 변형 필드는 지정된 키가 있는 레코드가 없는 경우 no-op일 수 있습니다. 마찬가지로 조회는 null 또는 빈 목록을 반환할 수 있습니다. 이러한 항목은 오류로 간주되지 않으므로 롤백을 트리거하지 않습니다.
이 결과를 방지하려면 @check 지시어를 사용하여 키를 찾을 수 있는지 테스트합니다.
# Delete by key, error if not found
mutation MustDeleteMovie($id: UUID!) @transaction {
movie_delete(id: $id) @check(expr: "this != null", message: "Movie not found, therefore nothing is deleted")
}
response 결합을 사용하여 다단계 변형 연결
관련 레코드(예: 새 Movie 및
연결된 MovieMetadata 항목)를 만드는 기본 접근 방식은 다음과 같습니다.
Movie의_insert변형을 호출합니다.- 생성된 영화의 반환된 키를 저장합니다.
- 그런 다음 두 번째
_insert변형을 호출하여MovieMetadata레코드를 만듭니다.
하지만 SQL Connect를 사용하면 두 번째 _insert에서 첫 번째 _insert의 결과에 액세스하여 이 일반적인 사례를 단일 다단계 작업으로 처리할 수 있습니다.
성공적인 영화 리뷰 앱을 만드는 것은 많은 작업입니다. 새로운 예시로 할 일 목록을 추적해 보겠습니다.
response를 사용하여 서버 값으로 필드 설정
다음 할 일 목록 변형에서
response결합은 현재 결합 이전의 모든 최상위 변형 필드를 포함하는 지금까지의 부분 응답 객체를 나타냅니다.- 초기
todoList_insert작업의 결과는id(키) 필드를 반환하며, 나중에response.todoList_insert.id에서 액세스하므로 새 할 일 항목을 즉시 삽입할 수 있습니다.
mutation CreateTodoListWithFirstItem(
$listName: String!,
$itemContent: String!
) @transaction {
# Sub-step 1:
todoList_insert(data: {
id_expr: "uuidV4()", # <-- auto-generated. Or a column-level @default on `type TodoList` will also work
name: $listName,
})
# Sub-step 2:
todo_insert(data: {
listId_expr: "response.todoList_insert.id" # <-- Grab the newly generated ID from the partial response so far.
content: $itemContent,
})
}
response를 사용하여 @check로 필드 검증
response는 @check(expr: "...")에서도 사용할 수 있으므로 이를 사용하여
훨씬 더 복잡한 서버 측 로직을 빌드할 수 있습니다. 변형의 query { … } 단계와 결합하면 추가 클라이언트-서버 왕복 없이 훨씬 더 많은 작업을 실행할 수 있습니다.
다음 예시에서 @check는 연결된 단계 후에 항상 실행되므로 @check가 이미 response.query에 액세스할 수 있습니다.
mutation CreateTodoInNamedList(
$listName: String!,
$itemContent: String!
) @transaction {
# Sub-step 1: Look up List.id by its name
query
@check(expr: "response.query.todoLists.size() > 0", message: "No such TodoList with the name!")
@check(expr: "response.query.todoLists.size() < 2", message: "Ambiguous listName!") {
todoLists(where: { name: $listName }) {
id
}
}
# Sub-step 2:
todo_insert(data: {
listId_expr: "response.todoLists[0].id" # <-- Now we have the parent list ID to insert to
content: $itemContent,
})
}
response 결합에 관한 자세한 내용은
CEL 참조를 참고하세요.
@transaction 및 query @check로 중단된 작업 이해
다단계 변형에서 오류가 발생할 수 있습니다.
- 데이터베이스 작업이 실패할 수 있습니다.
- query
@check로직이 작업을 종료할 수 있습니다.
SQL Connect는 다단계 변형과 함께 @transaction 지시어를 사용하는 것이 좋습니다. 이렇게 하면 클라이언트 코드에서 더 쉽게 처리할 수 있는 일관된 데이터베이스 및 변형 결과가 생성됩니다.
- 첫 번째 오류 또는 실패한
@check에서 작업이 종료되므로 후속 필드의 실행 또는 CEL 평가를 관리할 필요가 없습니다. - 롤백은 데이터베이스 오류 또는
@check로직에 대한 응답으로 실행되어 일관된 데이터베이스 상태를 생성합니다. - 롤백 오류는 항상 클라이언트 코드에 반환됩니다.
@transaction을 사용하지 않기로 선택하는 사용 사례가 있을 수 있습니다. 예를 들어 처리량, 확장성 또는 가용성이 더 높은 경우 eventual consistency를 선택할 수 있습니다. 하지만 결과를 허용하려면 데이터베이스와 클라이언트 코드를 관리해야 합니다.
- 데이터베이스 작업으로 인해 하나의 필드가 실패하면 후속 필드가 계속 실행됩니다. 하지만 실패한
@check는 여전히 전체 작업을 종료합니다. - 롤백이 실행되지 않습니다. 즉, 일부 업데이트는 성공하고 일부 업데이트는 실패한 혼합 데이터베이스 상태입니다.
@check로직이 이전 단계에서 읽기 또는 쓰기의 결과를 사용하는 경우@check를 사용한 작업에서 더 일관성 없는 결과가 발생할 수 있습니다.- 클라이언트 코드에 반환되는 결과에는 처리할 성공 및 실패 응답이 더 복잡하게 혼합되어 있습니다.
SQL Connect 변형의 지시어
유형 및 테이블을 정의하는 데 사용하는 지시어 외에도
SQL Connect는 작업의 동작을 보강하기 위해 @auth, @check, @redact 및
@transaction 지시어를 제공합니다.
| 지시어 | 적용 대상 | 설명 |
|---|---|---|
@auth |
쿼리 및 변형 | 쿼리 또는 변형의 승인 정책을 정의합니다. 승인 및 증명 가이드를 참고하세요. |
@check |
다단계 작업의 query 필드 |
지정된 필드가 쿼리 결과에 있는지 확인합니다. CEL (Common Expression Language) 표현식은 필드 값을 테스트하는 데 사용됩니다. 다단계 작업을 참고하세요 . |
@redact |
쿼리 | 클라이언트의 응답 일부를 수정합니다. 다단계 작업을 참고하세요 . |
@transaction |
변형 | 변형이 항상 데이터베이스 트랜잭션에서 실행되도록 합니다. 다단계 작업을 참고하세요 . |
다음 단계
관심 있을 만한 항목:
- AI 지원 도구를 사용하여 앱의 변형 생성
- 승인 가이드에 따라 변형 승인
- 웹, iOS, Android, Flutter용 클라이언트 코드에서 변형 호출
- 변형을 사용하여 대용량 데이터 작업 실행