Firebase Data Connect cho phép bạn tạo trình kết nối cho các phiên bản PostgreSQL được quản lý bằng Google Cloud SQL. Các trình kết nối này là sự kết hợp của các truy vấn và đột biến để sử dụng dữ liệu của bạn từ giản đồ.
Hướng dẫn bắt đầu đã giới thiệu một giản đồ ứng dụng đánh giá phim cho PostgreSQL.
Hướng dẫn đó cũng giới thiệu cả các thao tác quản trị có thể triển khai và đặc biệt, bao gồm cả các đột biến.
- Các đột biến có thể triển khai là những đột biến mà bạn triển khai để gọi từ các ứng dụng khách trong một trình kết nối, với các điểm cuối API mà bạn xác định. Data Connect tích hợp quy trình xác thực và uỷ quyền vào các đột biến này, đồng thời tạo SDK ứng dụng dựa trên API của bạn.
- Các hoạt động sửa đổi hành chính đặc biệt được chạy từ các môi trường có đặc quyền để điền sẵn và quản lý các bảng. Bạn có thể tạo và thực thi các truy vấn này trong bảng điều khiển Firebase, từ các môi trường có đặc quyền bằng cách sử dụng Firebase Admin SDK và trong các môi trường phát triển cục bộ bằng cách sử dụng tiện ích Data Connect VS Code của chúng tôi.
Hướng dẫn này xem xét kỹ hơn về các đột biến có thể triển khai.
Đặc điểm của đột biến Data Connect
Data Connect cho phép bạn thực hiện các đột biến cơ bản theo mọi cách mà bạn mong đợi khi có cơ sở dữ liệu PostgreSQL:
- Thực hiện các thao tác CRUD
- Quản lý các thao tác nhiều bước bằng giao dịch
Nhưng với các tiện ích của Data Connect cho GraphQL, bạn có thể triển khai các đột biến nâng cao để có các ứng dụng nhanh hơn và hiệu quả hơn:
- Sử dụng các đại lượng vô hướng khoá do nhiều thao tác trả về để đơn giản hoá các thao tác lặp lại trên bản ghi
- Sử dụng giá trị phía máy chủ để điền dữ liệu bằng các thao tác do máy chủ cung cấp
- Thực hiện các truy vấn trong quá trình thực hiện các thao tác đột biến nhiều bước để tra cứu dữ liệu, lưu các dòng mã và chuyến đi khứ hồi đến máy chủ.
Sử dụng các trường được tạo để triển khai đột biến
Các thao tác Data Connect sẽ mở rộng một tập hợp các trường Data Connect được tạo tự động dựa trên các loại và mối quan hệ loại trong giản đồ của bạn. Các trường này được tạo bằng công cụ cục bộ bất cứ khi nào bạn chỉnh sửa giản đồ.
Bạn có thể sử dụng các trường được tạo để triển khai các đột biến, từ việc tạo, cập nhật và xoá các bản ghi riêng lẻ trong các bảng đơn, cho đến các bản cập nhật phức tạp hơn cho nhiều bảng.Giả sử giản đồ của bạn chứa một loại Movie
và một loại Actor
được liên kết.
Data Connect tạo ra các trường movie_insert
, movie_update
, movie_delete
và nhiều trường khác.
Thay đổi với trường
movie_insert
Trường |
Sử dụng trường này để tạo một bộ phim. mutation CreateMovie($data: Movie_Data!) { movie_insert(data: $data) { key } } |
Thay đổi với trường
movie_update
Trường |
Sử dụng trường này để cập nhật một bộ phim theo khoá của bộ phim đó. mutation UpdateMovie($myKey: Movie_Key!, $data: Movie_Data!) { movie_update(key: $myKey, data: $data) { key } } |
Thay đổi với trường
movie_delete
Trường |
Sử dụng trường này để xoá một phim theo khoá của phim. mutation DeleteMovie($myKey: Movie_Key!) { movie_delete(key: $myKey) { key } } |
Các phần tử thiết yếu của một đột biến
Các đột biến Data Connect là các đột biến GraphQL có phần mở rộng Data Connect. Giống như với một đột biến GraphQL thông thường, bạn có thể xác định tên thao tác và danh sách các biến GraphQL.
Data Connect mở rộng các truy vấn GraphQL bằng các chỉ thị tuỳ chỉnh như @auth
và @transaction
.
Vì vậy, đột biến sau đây có:
- Định nghĩa kiểu
mutation
- Tên của một thao tác
SignUp
(biến đổi) - Một đối số thao tác
$username
có một biến - Một chỉ thị duy nhất,
@auth
- Một trường duy nhất
user_insert
.
mutation SignUp($username: String!) @auth(level: USER) {
user_insert(data: {
id_expr: "auth.uid"
username: $username
})
}
Mọi đối số đột biến đều yêu cầu một khai báo kiểu, một đối số tích hợp như String
hoặc một đối số tuỳ chỉnh, được xác định theo lược đồ như Movie
.
Viết các đột biến cơ bản
Bạn có thể bắt đầu viết các đột biến để tạo, cập nhật và xoá các bản ghi riêng lẻ khỏi cơ sở dữ liệu.
Tạo
Hãy tạo những nội dung cơ bản.
# 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
})
}
Hoặc một thao tác chèn và cập nhật.
# 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"
})
}
Thực hiện cập nhật
Sau đây là thông tin cập nhật. Nhà sản xuất và đạo diễn chắc chắn hy vọng rằng những mức đánh giá trung bình đó sẽ có xu hướng tăng.
Trường movie_update
chứa một đối số id
dự kiến để xác định một bản ghi và một trường data
mà bạn có thể dùng để đặt giá trị trong bản cập nhật này.
mutation UpdateMovie(
$id: UUID!,
$genre: String!,
$rating: Int!,
$description: String!
) {
movie_update(id: $id,
data: {
genre: $genre
rating: $rating
description: $description
})
}
Để thực hiện nhiều bản cập nhật, hãy sử dụng trường 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
})
}
Sử dụng các thao tác tăng, giảm, thêm và chèn vào đầu bằng _update
Trong khi có thể đặt giá trị một cách rõ ràng trong các đột biến _update
và _updateMany
, thì việc áp dụng một toán tử như tăng để cập nhật giá trị thường hợp lý hơn.data:
Để sửa đổi ví dụ cập nhật trước đó, giả sử bạn muốn tăng điểm xếp hạng của một bộ phim cụ thể. Bạn có thể sử dụng cú pháp rating_update
với toán tử inc
.
mutation UpdateMovie(
$id: UUID!,
$ratingIncrement: Int!
) {
movie_update(id: $id, data: {
rating_update: {
inc: $ratingIncrement
}
})
}
Data Connect hỗ trợ các toán tử sau đây cho việc cập nhật trường:
inc
để tăng các loại dữ liệuInt
,Int64
,Float
,Date
vàTimestamp
dec
để giảm các loại dữ liệuInt
,Int64
,Float
,Date
vàTimestamp
Đối với danh sách, bạn cũng có thể cập nhật bằng các giá trị riêng lẻ hoặc danh sách giá trị bằng cách sử dụng:
add
để thêm(các) mục nếu chúng chưa có trong các loại danh sách, ngoại trừ danh sách Vectorremove
để xoá tất cả các mục (nếu có) khỏi các loại danh sách, ngoại trừ danh sách vectơappend
để thêm(các) mục vào các loại danh sách, ngoại trừ danh sách Vectorprepend
để thêm(các) mục vào đầu các loại danh sách, ngoại trừ danh sách vectơ
Thực hiện thao tác xoá
Tất nhiên, bạn có thể xoá dữ liệu về phim. Chắc chắn những người bảo tồn phim sẽ muốn giữ gìn các bản phim vật lý càng lâu càng tốt.
# Delete by key
mutation DeleteMovie($id: UUID!) {
movie_delete(id: $id)
}
Tại đây, bạn có thể sử dụng _deleteMany
.
# Multiple deletes
mutation DeleteUnpopularMovies($minRating: Int!) {
movie_deleteMany(where: { rating: { le: $minRating } })
}
Viết đột biến trên các mối quan hệ
Quan sát cách sử dụng đột biến _upsert
ngầm trên một mối quan hệ.
# Create or update a one to one relation
mutation MovieMetadataUpsert($movieId: UUID!, $director: String!) {
movieMetadata_upsert(
data: { movie: { id: $movieId }, director: $director }
)
}
Thiết kế giản đồ cho các đột biến hiệu quả
Data Connect cung cấp 2 tính năng quan trọng cho phép bạn ghi các đột biến hiệu quả hơn và tiết kiệm các thao tác khứ hồi.
Khoá vô hướng là các giá trị nhận dạng đối tượng ngắn gọn mà Data Connect tự động tập hợp từ các trường khoá trong giản đồ của bạn. Các đại lượng vô hướng chính là về hiệu quả, cho phép bạn tìm thấy thông tin về danh tính và cấu trúc dữ liệu của mình trong một lệnh gọi duy nhất. Chúng đặc biệt hữu ích khi bạn muốn thực hiện các thao tác tuần tự trên các bản ghi mới và cần một giá trị nhận dạng duy nhất để truyền đến các thao tác sắp tới, cũng như khi bạn muốn truy cập vào các khoá quan hệ để thực hiện các thao tác phức tạp hơn.
Khi sử dụng giá trị máy chủ, bạn có thể cho phép máy chủ điền các trường trong bảng một cách linh hoạt bằng cách sử dụng các giá trị được lưu trữ hoặc có thể tính toán dễ dàng theo các biểu thức CEL phía máy chủ cụ thể trong đối số expr
. Ví dụ: bạn có thể xác định một trường có dấu thời gian được áp dụng khi trường được truy cập bằng thời gian được lưu trữ trong một yêu cầu thao tác, updatedAt: Timestamp!
@default(expr: "request.time")
.
Viết các đột biến nâng cao: cho phép Data Connect cung cấp các giá trị bằng cách sử dụng cú pháp field_expr
Như đã thảo luận trong các đại lượng khoá và giá trị máy chủ, bạn có thể thiết kế giản đồ để máy chủ điền các giá trị cho các trường phổ biến như id
và ngày để phản hồi các yêu cầu của ứng dụng.
Ngoài ra, bạn có thể sử dụng dữ liệu, chẳng hạn như mã nhận dạng người dùng, được gửi trong các đối tượng Data Connect request
từ ứng dụng khách.
Khi bạn triển khai các đột biến, hãy sử dụng cú pháp field_expr
để kích hoạt các bản cập nhật do máy chủ tạo hoặc truy cập vào dữ liệu từ các yêu cầu. Ví dụ: để truyền chế độ uỷ quyền uid
được lưu trữ trong một yêu cầu đến một thao tác _upsert
, hãy truyền "auth.uid"
trong trường 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 })
}
Hoặc trong một ứng dụng danh sách việc cần làm quen thuộc, khi tạo một danh sách việc cần làm mới, bạn có thể truyền id_expr
để hướng dẫn máy chủ tự động tạo một UUID cho danh sách.
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,
})
}
Để biết thêm thông tin, hãy xem các đại lượng vô hướng _Expr
trong tài liệu tham khảo về đại lượng vô hướng.
Viết các đột biến nâng cao: thao tác nhiều bước
Có nhiều trường hợp bạn có thể muốn đưa nhiều trường ghi (chẳng hạn như các mục chèn) vào một đột biến. Bạn cũng có thể muốn đọc cơ sở dữ liệu trong quá trình thực thi một đột biến để tra cứu và xác minh dữ liệu hiện có trước khi thực hiện, chẳng hạn như chèn hoặc cập nhật. Các lựa chọn này giúp tiết kiệm các thao tác khứ hồi và do đó tiết kiệm chi phí.
Data Connect cho phép bạn thực hiện logic nhiều bước trong các đột biến bằng cách hỗ trợ:
Nhiều trường ghi
Nhiều trường đọc trong các đột biến của bạn (sử dụng từ khoá trường
query
).Chỉ thị
@transaction
cung cấp khả năng hỗ trợ giao dịch quen thuộc từ cơ sở dữ liệu quan hệ.Chỉ thị
@check
cho phép bạn đánh giá nội dung của các lượt đọc bằng cách sử dụng biểu thức CEL và dựa trên kết quả của hoạt động đánh giá đó:- Tiến hành tạo, cập nhật và xoá theo định nghĩa của một đột biến
- Tiến hành trả về kết quả của một trường truy vấn
- Sử dụng các thông báo được trả về để thực hiện logic phù hợp trong mã ứng dụng
Chỉ thị
@redact
cho phép bạn bỏ qua kết quả trường truy vấn trong kết quả giao thức truyền dữ liệu.Liên kết CEL
response
, lưu trữ kết quả tích luỹ của tất cả các đột biến và truy vấn được thực hiện trong một thao tác phức tạp, nhiều bước. Bạn có thể truy cập vào liên kếtresponse
:- Trong các chỉ thị
@check
, thông qua đối sốexpr:
- Với các giá trị phía máy chủ, sử dụng cú pháp
field_expr
- Trong các chỉ thị
Lệnh @transaction
Hỗ trợ các đột biến nhiều bước, bao gồm cả việc xử lý lỗi bằng giao dịch.
Chỉ thị @transaction
đảm bảo rằng một đột biến (có một trường ghi duy nhất (ví dụ: _insert
hoặc _update
) hoặc có nhiều trường ghi) luôn chạy trong một giao dịch cơ sở dữ liệu.
Các đột biến không có
@transaction
sẽ thực thi từng trường gốc lần lượt theo trình tự. Thao tác này sẽ hiển thị mọi lỗi dưới dạng lỗi trường một phần, nhưng không phải là tác động của các lần thực thi tiếp theo.Các đột biến có
@transaction
được đảm bảo sẽ thành công hoàn toàn hoặc thất bại hoàn toàn. Nếu bất kỳ trường nào trong giao dịch không thành công, toàn bộ giao dịch sẽ được khôi phục.
Chỉ thị @check
và @redact
Lệnh @check
xác minh rằng các trường được chỉ định có trong kết quả truy vấn. Biểu thức Ngôn ngữ diễn đạt thông thường (CEL) được dùng để kiểm thử các giá trị trường. Hành vi mặc định của chỉ thị là kiểm tra và từ chối các nút có giá trị là null
hoặc []
(danh sách trống).
Chỉ thị @redact
sẽ biên tập một phần phản hồi từ máy khách. Các trường đã được chỉnh sửa vẫn được đánh giá về tác dụng phụ (bao gồm cả thay đổi dữ liệu và @check
) và kết quả vẫn có sẵn cho các bước sau trong biểu thức CEL.
Sử dụng @check
, @check(message:)
và @redact
Một mục đích sử dụng chính của @check
và @redact
là tra cứu dữ liệu liên quan để quyết định xem có nên uỷ quyền cho một số thao tác hay không, bằng cách sử dụng tra cứu trong logic nhưng ẩn thao tác đó khỏi ứng dụng khách. Truy vấn của bạn có thể trả về các thông báo hữu ích để xử lý chính xác trong mã ứng dụng.
Để minh hoạ, trường truy vấn sau đây sẽ kiểm tra xem người yêu cầu có vai trò "quản trị" phù hợp để xem những người dùng có thể chỉnh sửa một bộ phim hay không.
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
}
}
}
Để tìm hiểu thêm về các chỉ thị @check
và @redact
trong quá trình kiểm tra uỷ quyền, hãy tham khảo thảo luận về việc tra cứu dữ liệu uỷ quyền.
Sử dụng @check
để xác thực khoá
Một số trường đột biến, chẳng hạn như _update
, có thể không hoạt động nếu không tồn tại bản ghi có khoá được chỉ định. Tương tự, các thao tác tra cứu có thể trả về giá trị rỗng hoặc một danh sách trống. Đây không được coi là lỗi và do đó sẽ không kích hoạt quy trình khôi phục.
Để ngăn chặn kết quả này, hãy kiểm thử xem có thể tìm thấy các khoá bằng chỉ thị @check
hay không.
# 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")
}
Sử dụng liên kết response
để liên kết các đột biến nhiều bước
Phương pháp cơ bản để tạo các bản ghi liên quan, chẳng hạn như một Movie
mới và một mục MovieMetadata
được liên kết, là:
- Gọi một đột biến
_insert
choMovie
- Lưu khoá được trả về của phim đã tạo
- Sau đó, hãy gọi một đột biến
_insert
thứ hai để tạo bản ghiMovieMetadata
.
Nhưng với Data Connect, bạn có thể xử lý trường hợp phổ biến này trong một thao tác nhiều bước bằng cách truy cập vào kết quả của _insert
đầu tiên trong _insert
thứ hai.
Việc tạo một ứng dụng đánh giá phim thành công là một quá trình đòi hỏi nhiều công sức. Hãy theo dõi danh sách việc cần làm bằng một ví dụ mới.
Sử dụng response
để đặt các trường có giá trị phía máy chủ
Trong thao tác đột biến danh sách việc cần làm sau đây:
- Liên kết
response
đại diện cho đối tượng phản hồi một phần cho đến thời điểm hiện tại, bao gồm tất cả các trường đột biến cấp cao nhất trước trường hiện tại. - Kết quả của thao tác
todoList_insert
ban đầu (trả về trườngid
(khoá)) sẽ được truy cập sau trongresponse.todoList_insert.id
để chúng ta có thể chèn ngay một việc cần làm mới.
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,
})
}
Sử dụng response
để xác thực các trường bằng @check
response
cũng có trong @check(expr: "...")
, vì vậy, bạn có thể dùng công cụ này để xây dựng logic phía máy chủ phức tạp hơn nữa. Khi kết hợp với các bước query { … }
trong đột biến, bạn có thể đạt được nhiều kết quả hơn mà không cần thêm bất kỳ chuyến khứ hồi nào giữa máy khách và máy chủ.
Trong ví dụ sau, xin lưu ý rằng @check
đã có quyền truy cập vào response.query
vì @check
luôn chạy sau bước mà nó được đính kèm.
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,
})
}
Để biết thêm thông tin về liên kết response
, hãy xem tài liệu tham khảo về CEL.
Tìm hiểu về các thao tác bị gián đoạn bằng @transaction
và query @check
Các đột biến nhiều bước có thể gặp phải lỗi:
- Các thao tác trên cơ sở dữ liệu có thể không thực hiện được.
- Logic truy vấn
@check
có thể chấm dứt các thao tác.
Data Connect đề xuất bạn sử dụng chỉ thị @transaction
với các đột biến nhiều bước. Điều này giúp cơ sở dữ liệu nhất quán hơn và kết quả đột biến dễ xử lý hơn trong mã ứng dụng:
- Khi gặp lỗi đầu tiên hoặc
@check
không thành công, thao tác sẽ kết thúc, vì vậy, bạn không cần quản lý việc thực thi bất kỳ trường nào tiếp theo hoặc đánh giá CEL. - Các thao tác khôi phục được thực hiện để phản hồi các lỗi cơ sở dữ liệu hoặc logic
@check
, mang lại trạng thái nhất quán cho cơ sở dữ liệu. - Lỗi khôi phục luôn được trả về mã ứng dụng khách.
Có thể có một số trường hợp sử dụng mà bạn chọn không dùng @transaction
: bạn có thể chọn tính nhất quán sau cùng nếu, ví dụ: bạn cần thông lượng, khả năng mở rộng hoặc tính sẵn có cao hơn. Tuy nhiên, bạn cần quản lý cơ sở dữ liệu và mã ứng dụng để cho phép các kết quả:
- Nếu một trường không thành công do các thao tác trên cơ sở dữ liệu, thì các trường tiếp theo sẽ tiếp tục thực thi. Tuy nhiên, các
@check
không thành công vẫn sẽ kết thúc toàn bộ thao tác. - Không thực hiện việc khôi phục, tức là trạng thái cơ sở dữ liệu hỗn hợp với một số bản cập nhật thành công và một số bản cập nhật không thành công.
- Các thao tác của bạn với
@check
có thể cho ra kết quả không nhất quán hơn nếu logic@check
sử dụng kết quả của các thao tác đọc và/hoặc ghi ở bước trước. - Kết quả trả về cho mã ứng dụng sẽ chứa nhiều phản hồi thành công và thất bại phức tạp hơn cần được xử lý.
Chỉ thị cho các đột biến Data Connect
Ngoài các chỉ thị mà bạn dùng để xác định các loại và bảng, Data Connect còn cung cấp các chỉ thị @auth
, @check
, @redact
và @transaction
để tăng cường hành vi của các thao tác.
Chỉ thị | Áp dụng cho | Mô tả |
---|---|---|
@auth |
Truy vấn và đột biến | Xác định chính sách uỷ quyền cho một truy vấn hoặc đột biến. Hãy xem hướng dẫn uỷ quyền và chứng thực. |
@check |
Các trường query trong các thao tác nhiều bước |
Xác minh rằng các trường được chỉ định có trong kết quả truy vấn. Một biểu thức Ngôn ngữ diễn đạt thông thường (CEL) được dùng để kiểm thử các giá trị trường. Xem phần Thao tác nhiều bước. |
@redact |
Cụm từ tìm kiếm | Chỉnh sửa một phần của câu trả lời từ ứng dụng khách. Xem phần Thao tác nhiều bước. |
@transaction |
Đột biến | Đảm bảo rằng một đột biến luôn chạy trong giao dịch cơ sở dữ liệu. Xem phần Thao tác nhiều bước. |
Các bước tiếp theo
Bạn có thể quan tâm đến:
- Tạo các biến thể cho ứng dụng bằng các công cụ hỗ trợ AI
- Uỷ quyền cho các đột biến theo hướng dẫn uỷ quyền
- Gọi các đột biến từ mã ứng dụng của bạn cho web, iOS, Android và Flutter.
- Thực hiện các thao tác dữ liệu hàng loạt bằng cách biến đổi