Firebase SQL Connect cho phép bạn tạo trình kết nối cho các thực thể PostgreSQL được quản lý bằng 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à phép biến đổi để sử dụng dữ liệu từ giản đồ của bạn.
Hướng dẫn Bắt đầu đã giới thiệu 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à thao tác quản trị đặc biệt, bao gồm cả phép biến đổi.
- Phép biến đổi có thể triển khai là những phép biến đổi 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. SQL Connect tích hợp tính năng xác thực và uỷ quyền vào các phép biến đổi này, đồng thời tạo SDK ứng dụng dựa trên API của bạn.
- Phép biến đổi quản trị đặc biệt được chạy từ các môi trường có đặc quyền để điền và quản lý bảng. Bạn có thể tạo và thực thi các phép biến đổi 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 SQL Connect VS Code.
Hướng dẫn này sẽ xem xét kỹ hơn về phép biến đổi có thể triển khai.
Các tính năng của SQL Connect phép biến đổi
SQL Connect cho phép bạn thực hiện các phép biến đổi cơ bản theo tất cả các 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
Tuy nhiên, với các tiện ích của SQL Connect's cho GraphQL, bạn có thể triển khai các phép biến đổi 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 các giá trị 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 biến đổi nhiều bước để tra cứu dữ liệu, lưu các dòng mã và các chuyến khứ hồi đến máy chủ.
Sử dụng các trường được tạo để triển khai phép biến đổi
Các thao tác SQL Connect sẽ mở rộng một tập hợp các trường do SQL Connect tự động tạo 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ộ mỗi khi 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 phép biến đổi, 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 lẻ, đến các bản cập nhật nhiều bảng phức tạp hơn.Giả sử giản đồ của bạn chứa loại Movie và loại Actor được liên kết.
SQL Connect tạo các trường movie_insert,
movie_update, movie_delete và nhiều trường khác.
Phép biến đổi với trường
movie_insert
|
Trường |
Sử dụng trường này để tạo một bộ phim. mutation CreateMovie($title: String!, $releaseYear: Int!, $genre: String!, $rating: Int!) { movie_insert(data: { title: $title releaseYear: $releaseYear genre: $genre rating: $rating }) } |
Phép biến đổ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!, $genre: String, $rating: Int, $description: String) { movie_update(key: $myKey, data: { genre: $genre rating: $rating description: $description }) } |
Phép biến đổi với trường
movie_delete
|
Trường |
Sử dụng trường này để xoá một bộ phim theo khoá của bộ phim đó. mutation DeleteMovie($myKey: Movie_Key!) { movie_delete(key: $myKey) { key } } |
Các thành phần thiết yếu của phép biến đổi
SQL Connect phép biến đổi là phép biến đổi GraphQL có SQL Connect tiện ích. Giống như phép biến đổi 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.
SQL Connect mở rộng các truy vấn GraphQL bằng các lệnh tuỳ chỉnh như
@auth và @transaction.
Vì vậy, phép biến đổi sau đây có:
- Định nghĩa loại
mutation - Tên thao tác (phép biến đổi)
SignUp - Một đối số thao tác biến
$username - Một lệnh 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ố biến đổi đều yêu cầu khai báo loại, một loại tích hợp sẵn như String hoặc một loại tuỳ chỉnh do giản đồ xác định như Movie.
Viết phép biến đổi cơ bản
Bạn có thể bắt đầu viết phép biến đổi để 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 các thao tác 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 thao tác chèn hoặc 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à các bản cập nhật. Nhà sản xuất và đạo diễn chắc chắn hy vọng rằng những điểm xếp hạng trung bình đó đang theo xu hướng.
Trường movie_update chứa đối số id dự kiến để xác định một bản ghi và trường data mà bạn có thể sử dụng để đặt các 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 trước với _update
Trong khi các phép biến đổi _update và _updateMany cho phép bạn đặt giá trị một cách rõ ràng trong
data:, thì việc áp dụng một toán tử như tăng để cập nhật
các giá trị thường hợp lý hơn.
Để sửa đổi ví dụ cập nhật trước đó, hãy 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
}
})
}
SQL Connect hỗ trợ các toán tử sau đây để cập nhật trường:
incđể tăng các loại dữ liệuInt,Int64,Float,DatevàTimestampdecđể giảm các loại dữ liệuInt,Int64,Float,Datevà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 các mục đó 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 Vectorappendđể thêm(các) mục vào các loại danh sách, ngoại trừ danh sách Vectorprependđể chèn(các) mục vào các loại danh sách, ngoại trừ danh sách Vector
Thực hiện thao tác xoá
Tất nhiên, bạn có thể xoá dữ liệu phim. Những người bảo tồn phim chắc chắn sẽ muốn duy trì các bộ 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 phép biến đổi trên các mối quan hệ
Hãy quan sát cách sử dụng phép biến đổi _upsert ngầm ẩn 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 phép biến đổi hiệu quả
SQL Connect cung cấp 2 tính năng quan trọng cho phép bạn viết các phép biến đổi hiệu quả hơn và lưu các thao tác khứ hồi.
Các đại lượng vô hướng khoá là các giá trị nhận dạng đối tượng ngắn gọn mà SQL 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 khoá giúp tăng hiệu quả, cho phép bạn tìm 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. Các đại lượng này đặc biệt hữu ích khi bạn muốn thực hiện các hành động 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 để chuyển cho 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 các giá trị máy chủ, bạn có thể cho phép máy chủ điền
các trường trong bảng của bạn một cách hiệu quả bằ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 cụ thể phía máy chủ 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 yêu cầu thao tác, updatedAt: Timestamp!
@default(expr: "request.time").
Viết phép biến đổi nâng cao: cho phép SQL Connect cung cấp các giá trị bằng cú pháp field_expr
Như đã thảo luận trong các đại lượng vô hướ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ư ids 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
SQL Connect request đối tượng từ các ứng dụng khách.
Khi triển khai phép biến đổi, 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 dữ liệu từ các yêu cầu. Ví dụ: để chuyển
quyền uỷ quyền uid được lưu trữ trong một yêu cầu đến thao tác _upsert operation, hãy chuyển
"auth.uid" trong trường userId_expr field.
# 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 danh sách việc cần làm mới, bạn có thể chuyển id_expr để hướng dẫn máy chủ tự động tạo 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 phép biến đổi nâng cao: các thao tác nhiều bước
Có nhiều trường hợp mà bạn có thể muốn đưa nhiều trường ghi (như chèn) vào một phép biến đổi. Bạn cũng có thể muốn đọc cơ sở dữ liệu trong quá trình thực thi phép biến đổi để tra cứu và xác minh dữ liệu hiện có trước khi thực hiện, ví dụ: 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í.
SQL Connect cho phép bạn thực hiện logic nhiều bước trong các phép biến đổi bằng cách hỗ trợ:
Nhiều trường ghi
Nhiều trường đọc trong các phép biến đổi (sử dụng từ khoá trường
query).Lệnh
@transactiondirective, cung cấp tính năng hỗ trợ giao dịch quen thuộc từ cơ sở dữ liệu quan hệ.Lệnh
@checkdirective, cho phép bạn đánh giá nội dung của các lần đọc bằng cách sử dụng biểu thức CEL và dựa trên kết quả của việc đánh giá đó:- Tiến hành tạo, cập nhật và xoá do phép biến đổi xác định
- Tiến hành trả về kết quả của trường truy vấn
- Sử dụng các thông báo được trả về để thực hiện logic thích hợp trong mã ứng dụng
Lệnh
@redactdirective, cho phép bạn bỏ qua kết quả trường truy vấn khỏi kết quả giao thức truyền dữ liệu.Liên kết
responseCEL, lưu trữ kết quả tích luỹ của tất cả các phép biến đổi 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 lệnh
@check, thông qua đối sốexpr: - Với các giá trị máy chủ, sử dụng cú pháp
field_expr
- Trong các lệnh
Lệnh @transaction
Tính năng hỗ trợ cho các phép biến đổi nhiều bước bao gồm xử lý lỗi bằng giao dịch.
Lệnh @transaction thực thi rằng một phép biến đổi (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 phép biến đổi không có
@transactionsẽ 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 hiển thị tác động của các lần thực thi tiếp theo.Các phép biến đổi 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 thất bại, toàn bộ giao dịch sẽ được khôi phục.
Các lệnh @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 lệnh là kiểm tra và từ chối các nút có giá trị là null hoặc [] (danh sách trống).
Lệnh @redact sẽ chỉnh sửa một phần của phản hồi từ ứng dụng. Các trường đã chỉnh sửa vẫn được đánh giá về các tác dụng phụ (bao gồm cả các thay đổi về 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 tính năng tra cứu trong logic nhưng ẩn tính năng này khỏi ứng dụng. 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.
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 lệnh @check và @redact trong các lượt kiểm tra uỷ quyền,
hãy tham khảo phần thảo luận về tính năng tra cứu dữ liệu uỷ quyền.
Sử dụng @check để xác thực khoá
Một số trường biến đổi, 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 lượt tra cứu có thể trả về giá trị null hoặc danh sách trống. Đây không được coi là lỗi và do đó sẽ không kích hoạt việc khôi phục.
Để tránh kết quả này, hãy kiểm thử xem có thể tìm thấy khoá bằng cách sử dụng lệnh @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 phép biến đổi nhiều bước
Phương pháp cơ bản để tạo các bản ghi liên quan, ví dụ: một Movie mới và
một mục MovieMetadata được liên kết, là:
- Gọi phép biến đổi
_insertchoMovie - Lưu trữ khoá được trả về của bộ phim đã tạo
- Sau đó, gọi phép biến đổi
_insertthứ hai để tạo bản ghiMovieMetadata.
Tuy nhiên, với SQL 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
thứ hai _insert.
Việc tạo một ứng dụng đánh giá phim thành công là một công việc khó khăn. Hãy theo dõi danh sách việc cần làm của chúng ta bằng một ví dụ mới.
Sử dụng response để đặt các trường có giá trị máy chủ
Trong phép biến đổi 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 nay, bao gồm tất cả các trường biến đổi cấp cao nhất trước trường hiện tại. - Kết quả của thao tác
todoList_insertban đầ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 mục 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ể sử dụng để
xây dựng logic phía máy chủ phức tạp hơn. Khi kết hợp với các bước query { … } trong các phép biến đổi, bạn có thể đạt được nhiều kết quả hơn mà không cần thực hiện thêm các chuyến khứ hồi giữa ứng dụng và máy chủ.
Trong ví dụ sau, hãy lưu ý: @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 các thao tác bị gián đoạn bằng @transaction và query @check
Các phép biến đổi nhiều bước có thể gặp lỗi:
- Các thao tác cơ sở dữ liệu có thể không thành công.
- Logic truy vấn
@checkcó thể chấm dứt các thao tác.
SQL Connect khuyên bạn nên sử dụng lệnh @transaction với
các phép biến đổi nhiều bước. Điều này giúp cơ sở dữ liệu và kết quả biến đổi nhất quán hơn, dễ xử lý hơn trong mã ứng dụng:
- Khi gặp lỗi đầu tiên hoặc
@checkkhông thành công, thao tác sẽ chấm dứt, vì vậy, bạn không cần quản lý việc thực thi bất kỳ trường tiếp theo nào hoặc đánh giá CEL. - Việ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 cơ sở dữ liệu nhất quán. - Lỗi khôi phục luôn được trả về mã ứng dụng.
Có thể có một số trường hợp sử dụng mà bạn chọn không sử dụng @transaction: bạn có thể chọn tính nhất quán cuối cùng nếu, ví dụ: bạn cần công suất, khả năng có thể mở rộng hoặc tính khả dụng 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 cơ sở dữ liệu, các trường tiếp theo sẽ tiếp tục thực thi. Tuy nhiên, các
@checkkhông thành công vẫn chấm dứt toàn bộ thao tác. - Việc khôi phục không được thực hiện, nghĩa 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
@checkcó thể cho kết quả không nhất quán hơn nếu logic@checksử dụng kết quả của các lần đọc và/hoặc ghi ở bước trước. - Kết quả được trả về mã ứng dụng sẽ chứa hỗn hợp phức tạp hơn giữa các phản hồi thành công và không thành công để xử lý.
Các lệnh cho phép biến đổi SQL Connect
Ngoài các lệnh mà bạn sử dụng để xác định các loại và bảng,
SQL Connect cung cấp các lệnh @auth, @check, @redact và
@transaction để tăng cường hành vi của các thao tác.
| Lệnh | Áp dụng cho | Mô tả |
|---|---|---|
@auth |
Truy vấn và phép biến đổi | Xác định chính sách uỷ quyền cho một truy vấn hoặc phép biến đổi. Xem hướng dẫn về 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. 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 bài viết Các 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 phản hồi từ ứng dụng. Xem bài viết Các thao tác nhiều bước. |
@transaction |
Phép biến đổi | Thực thi rằng một phép biến đổi luôn chạy trong một giao dịch cơ sở dữ liệu. Xem bài viết Các thao tác nhiều bước. |
Các bước tiếp theo
Bạn có thể quan tâm đến:
- Tạo phép biến đổi cho ứng dụng bằng các công cụ hỗ trợ AI
- Uỷ quyền cho các phép biến đổi theo hướng dẫn uỷ quyền
- Gọi phép biến đổi từ mã ứng dụng cho web, iOS, Android và Flutter.
- Thực hiện các thao tác dữ liệu hàng loạt bằng phép biến đổi