8.2 KiB
8.2 KiB
Operations Reference
Contents
Generated Fields
Data Connect auto-generates fields for each @table type:
| Generated Field | Purpose | Example |
|---|---|---|
movie(id: UUID, key: Key, first: Row) |
Get single record | movie(id: $id) or movie(first: {where: ...}) |
movies(where: ..., orderBy: ..., limit: ..., offset: ..., distinct: ..., having: ...) |
List/filter records | movies(where: {...}) |
movie_insert(data: ...) |
Create record | Returns key |
movie_insertMany(data: [...]) |
Bulk create | Returns keys |
movie_update(id: ..., data: ...) |
Update by ID | Returns key or null |
movie_updateMany(where: ..., data: ...) |
Bulk update | Returns count |
movie_upsert(data: ...) |
Insert or update | Returns key |
movie_delete(id: ...) |
Delete by ID | Returns key or null |
movie_deleteMany(where: ...) |
Bulk delete | Returns count |
Relation Fields
For a Post with author: User!:
post.author- Navigate to related Useruser.posts_on_author- Reverse: all Posts by User
For many-to-many via MovieActor:
movie.actors_via_MovieActor- Get all actorsactor.movies_via_MovieActor- Get all movies
Queries
Basic Query
query GetMovie($id: UUID!) @auth(level: PUBLIC) {
movie(id: $id) {
id title genre releaseYear
}
}
List with Filtering
query ListMovies($genre: String, $minRating: Int) @auth(level: PUBLIC) {
movies(
where: {
genre: { eq: $genre },
rating: { ge: $minRating }
},
orderBy: [{ releaseYear: DESC }, { title: ASC }],
limit: 20,
offset: 0
) {
id title genre rating
}
}
Filter Operators
| Operator | Description | Example |
|---|---|---|
eq |
Equals | { title: { eq: "Matrix" }} |
ne |
Not equals | { status: { ne: "deleted" }} |
gt, ge |
Greater than (or equal) | { rating: { ge: 4 }} |
lt, le |
Less than (or equal) | { releaseYear: { lt: 2000 }} |
in |
In list | { genre: { in: ["Action", "Drama"] }} |
nin |
Not in list | { status: { nin: ["deleted", "hidden"] }} |
isNull |
Is null check | { description: { isNull: true }} |
contains |
String contains | { title: { contains: "war" }} |
startsWith |
String starts with | { title: { startsWith: "The" }} |
endsWith |
String ends with | { email: { endsWith: "@gmail.com" }} |
includes |
Array includes | { tags: { includes: "sci-fi" }} |
Expression Operators (Compare with Server Values)
Use _expr suffix to compare with server-side values:
query MyPosts @auth(level: USER) {
posts(where: { authorUid: { eq_expr: "auth.uid" }}) {
id title
}
}
query RecentPosts @auth(level: PUBLIC) {
posts(where: { publishedAt: { lt_expr: "request.time" }}) {
id title
}
}
Logical Operators
query ComplexFilter($genre: String, $minRating: Int) @auth(level: PUBLIC) {
movies(where: {
_or: [
{ genre: { eq: $genre }},
{ rating: { ge: $minRating }}
],
_and: [
{ releaseYear: { ge: 2000 }},
{ status: { ne: "hidden" }}
],
_not: { genre: { eq: "Horror" }}
}) { id title }
}
Relational Queries
# Navigate relationships
query MovieWithDetails($id: UUID!) @auth(level: PUBLIC) {
movie(id: $id) {
title
# One-to-one
metadata: movieMetadata_on_movie { director }
# One-to-many
reviews: reviews_on_movie { rating user { name }}
# Many-to-many
actors: actors_via_MovieActor { name }
}
}
# Filter by related data
query MoviesByDirector($director: String!) @auth(level: PUBLIC) {
movies(where: {
movieMetadata_on_movie: { director: { eq: $director }}
}) { id title }
}
Aliases
query CompareRatings($genre: String!) @auth(level: PUBLIC) {
highRated: movies(where: { genre: { eq: $genre }, rating: { ge: 8 }}) {
title rating
}
lowRated: movies(where: { genre: { eq: $genre }, rating: { lt: 5 }}) {
title rating
}
}
Mutations
Create
mutation CreateMovie($title: String!, $genre: String) @auth(level: USER) {
movie_insert(data: {
title: $title,
genre: $genre
})
}
Create with Server Values
mutation CreatePost($title: String!, $content: String!) @auth(level: USER) {
post_insert(data: {
authorUid_expr: "auth.uid", # Current user
id_expr: "uuidV4()", # Auto-generate UUID
createdAt_expr: "request.time", # Server timestamp
title: $title,
content: $content
})
}
Update
mutation UpdateMovie($id: UUID!, $title: String, $genre: String) @auth(level: USER) {
movie_update(
id: $id,
data: {
title: $title,
genre: $genre,
updatedAt_expr: "request.time"
}
)
}
Update Operators
mutation IncrementViews($id: UUID!) @auth(level: PUBLIC) {
movie_update(id: $id, data: {
viewCount_update: { inc: 1 }
})
}
mutation AddTag($id: UUID!, $tag: String!) @auth(level: USER) {
movie_update(id: $id, data: {
tags_update: { add: [$tag] } # add, remove, append, prepend
})
}
| Operator | Types | Description |
|---|---|---|
inc |
Int, Float, Date, Timestamp | Increment value |
dec |
Int, Float, Date, Timestamp | Decrement value |
add |
Lists | Add items if not present |
remove |
Lists | Remove all matching items |
append |
Lists | Append to end |
prepend |
Lists | Prepend to start |
Upsert
mutation UpsertUser($email: String!, $name: String!) @auth(level: USER) {
user_upsert(data: {
uid_expr: "auth.uid",
email: $email,
name: $name
})
}
Delete
mutation DeleteMovie($id: UUID!) @auth(level: USER) {
movie_delete(id: $id)
}
mutation DeleteOldDrafts @auth(level: USER) {
post_deleteMany(where: {
status: { eq: "draft" },
createdAt: { lt_time: { now: true, sub: { days: 30 }}}
})
}
Filtered Updates/Deletes (User-Owned)
mutation UpdateMyPost($id: UUID!, $content: String!) @auth(level: USER) {
post_update(
first: { where: {
id: { eq: $id },
authorUid: { eq_expr: "auth.uid" } # Only own posts
}},
data: { content: $content }
)
}
Key Scalars
Key scalars (Movie_Key, User_Key) are auto-generated types representing primary keys:
# Using key scalar
query GetMovie($key: Movie_Key!) @auth(level: PUBLIC) {
movie(key: $key) { title }
}
# Variable format
# { "key": { "id": "uuid-here" } }
# Composite key
# { "key": { "movieId": "...", "userId": "..." } }
Key scalars are returned by mutations:
mutation CreateAndFetch($title: String!) @auth(level: USER) {
key: movie_insert(data: { title: $title })
# Returns: { "key": { "id": "generated-uuid" } }
}
Multi-Step Operations
@transaction
Ensures atomicity - all steps succeed or all rollback:
mutation CreateUserWithProfile($name: String!, $bio: String!)
@auth(level: USER)
@transaction {
# Step 1: Create user
user_insert(data: {
uid_expr: "auth.uid",
name: $name
})
# Step 2: Create profile (uses response from step 1)
userProfile_insert(data: {
userId_expr: "response.user_insert.uid",
bio: $bio
})
}
Using response Binding
Access results from previous steps:
mutation CreateTodoWithItem($listName: String!, $itemText: String!)
@auth(level: USER)
@transaction {
todoList_insert(data: {
id_expr: "uuidV4()",
name: $listName
})
todoItem_insert(data: {
listId_expr: "response.todoList_insert.id", # From previous step
text: $itemText
})
}
Embedded Queries
Run queries within mutations for validation:
mutation AddToPublicList($listId: UUID!, $item: String!)
@auth(level: USER)
@transaction {
# Step 1: Verify list exists and is public
query @redact {
todoList(id: $listId) @check(expr: "this != null", message: "List not found") {
isPublic @check(expr: "this == true", message: "List is not public")
}
}
# Step 2: Add item
todoItem_insert(data: { listId: $listId, text: $item })
}