User 

This page documents the user model.

Data Shape 

Gadget's database stores user records by storing and retrieving each of the fields defined on the model in the Gadget Editor to a managed database. Gadget has generated a GraphQL type matching the configured fields for user:

user Schema
1export type User = {
2
3 __typename: 'User';
4
5 /** The globally unique, unchanging identifier for this record. Assigned and managed by Gadget. */
6 id: string;
7
8 /** The time at which this record was first created. Set once upon record creation and never changed. Managed by Gadget. */
9 createdAt: Date;
10
11 /** The time at which this record was last changed. Set each time the record is successfully acted upon by an action. Managed by Gadget. */
12 updatedAt: Date;
13
14 lastSignedIn: Date;
15
16 roles: Role[];
17
18 lastName: string;
19
20 email: string;
21
22 googleImageUrl: string;
23
24 firstName: string;
25
26 /** Get all the fields for this record. Useful for not having to list out all the fields you want to retrieve, but slower. */
27 _all: Record<string, any>;
28};
1type User {
2 """
3 The globally unique, unchanging identifier for this record. Assigned and managed by Gadget.
4 """
5 id: GadgetID!
6
7 """
8 The time at which this record was first created. Set once upon record creation and never changed. Managed by Gadget.
9 """
10 createdAt: DateTime!
11
12 """
13 The time at which this record was last changed. Set each time the record is successfully acted upon by an action. Managed by Gadget.
14 """
15 updatedAt: DateTime!
16 lastSignedIn: DateTime
17 roles: [Role!]
18 lastName: String
19 email: EmailAddress!
20 googleImageUrl: URL
21 firstName: String
22
23 """
24 Get all the fields for this record. Useful for not having to list out all the fields you want to retrieve, but slower.
25 """
26 _all: JSONObject!
27}

You can preview what a real record's shape looks like by fetching it using the  openai-screenwriter-tutorial-v2 API playground.

Any fetched user record will have this same User type, and expose the same data by default, regardless of if it's fetched by ID or as part of a findMany. This means you can select any of the record's fields wherever you like in a GraphQL query according to the use case at hand.

Retrieving one user record 

Individual user records can be retrieved using the "find by ID" API endpoint. You can also return only some fields, or extra fields beyond what Gadget retrieves by default, using the select option.

The findOne function throws an error if no matching record is found, which you will need to catch and handle. Alternatively, you can use the maybeFindOne function, which returns null if no record is found, without throwing an error.

Similarly, the useFindOne React hook returns (but does not throw) an error when no matching record is found, while the useMaybeFindOne hook simply returns null if no record is found, without also returning an error.

Get one user
const userRecord = await api.user.findOne("123");
// => a string
console.log(userRecord.id);
// => a Date object
console.log(userRecord.createdAt);
1const FindOneComponent = () => {
2 const [{data, error, fetching}, refresh] = useFindOne(api.user, "123");
3
4// => a string
5console.log(data?.id);
6// => a Date object
7console.log(data?.createdAt);
8
9return <>{JSON.stringify(data)}</>;
10};
1query GetOneUser($id: GadgetID!) {
2 user(id: $id) {
3 __typename
4 id
5
6 # ...
7
8 createdAt
9 email
10 firstName
11 googleImageUrl
12 lastName
13 lastSignedIn
14 roles {
15 key
16 name
17 }
18 updatedAt
19 }
20}
Variables
json
{ "id": "123" }
const userRecord = await api.user.findOne("123");
// => a string
console.log(userRecord.id);
// => a Date object
console.log(userRecord.createdAt);
1const FindOneComponent = () => {
2 const [{data, error, fetching}, refresh] = useFindOne(api.user, "123");
3
4// => a string
5console.log(data?.id);
6// => a Date object
7console.log(data?.createdAt);
8
9return <>{JSON.stringify(data)}</>;
10};

Retrieving the first of many user records 

The first record from a list of records can be retrieved using the "find first" API endpoint. The source list of records can be filtered using the filter option, sorted using the sort option, searched using the search option, though no pagination options are available on this endpoint. You can also return only some fields, or extra fields beyond what Gadget retrieves by default using the select option.

The findFirst function throws an error if no matching record is found, which you will need to catch and handle. Alternatively, you can use the maybeFindFirst function, which returns null if no record is found, without throwing an error.

Similarly, the useFindFirst React hook returns (but does not throw) an error when no matching record is found, while the useMaybeFindFirst hook simply returns null if no record is found, without also returning an error.

Get first user
const userRecord = await api.user.findFirst();
console.log(userRecord.id); //=> a string
console.log(userRecord.createdAt); //=> a Date object
1const FindFirstComponent = (props) => {
2 const [{data, error, fetching}, refresh] = useFindFirst(api.user);
3
4// => a string
5console.log(data?.id)
6// => a Date object
7console.log(data?.createdAt)
8
9return <>{JSON.stringify(data)}</>;
10};
1query FindManyUsers(
2 $first: Int
3 $search: String
4 $sort: [UserSort!]
5 $filter: [UserFilter!]
6) {
7 users(first: $first, search: $search, sort: $sort, filter: $filter) {
8 edges {
9 node {
10 __typename
11 id
12
13 # ...
14
15 createdAt
16 email
17 firstName
18 googleImageUrl
19 lastName
20 lastSignedIn
21 roles {
22 key
23 name
24 }
25 updatedAt
26 }
27 }
28 }
29}
Variables
json
{ "first": 1 }
const userRecord = await api.user.findFirst();
console.log(userRecord.id); //=> a string
console.log(userRecord.createdAt); //=> a Date object
1const FindFirstComponent = (props) => {
2 const [{data, error, fetching}, refresh] = useFindFirst(api.user);
3
4// => a string
5console.log(data?.id)
6// => a Date object
7console.log(data?.createdAt)
8
9return <>{JSON.stringify(data)}</>;
10};

Retrieving many user records 

Pages of user records can be retrieved by using the "find many" API endpoint. The returned records can be filtered using the filter option, sorted using the sort option, searched using the search option, and paginated using standard Relay-style pagination options. You can also return only some fields, or extra fields beyond what Gadget retrieves by default using the select option.

This GraphQL endpoint returns records in the Relay Connection style (as a list of edges with nodes and cursors) so they can be paginated. The users GraphQL endpoint works with any Relay-compatible caching client, or you can use Gadget's JS client for pagination with the findMany function.

Find a page of users 

You can fetch one page of records with the user.findMany JS method or the users GraphQL field. No options are required, and records can be sorted with the sort option and filtered with the filter optional. The records returned will be implicitly sorted by ID ascending, unless you pass a sort option.

Find many users
const userRecords = await api.user.findMany();
// => a number
console.log(userRecords.length);
// => a string
console.log(userRecords[0].id);
1const FindManyComponent = () => {
2 const [{data, error, fetching}, refresh] = useFindMany(api.user);
3if (!data) return null;
4
5// => a number
6console.log(data.length)
7
8return <>
9{data.map(record => JSON.stringify(record))}
10
11 </>
12};
1query FindManyUsers(
2 $after: String
3 $before: String
4 $first: Int
5 $last: Int
6 $search: String
7 $sort: [UserSort!]
8 $filter: [UserFilter!]
9) {
10 users(
11 after: $after
12 before: $before
13 first: $first
14 last: $last
15 search: $search
16 sort: $sort
17 filter: $filter
18 ) {
19 edges {
20 node {
21 __typename
22 id
23
24 # ...
25
26 createdAt
27 lastSignedIn
28 updatedAt
29 }
30 }
31 }
32}
Variables
json
{}
const userRecords = await api.user.findMany();
// => a number
console.log(userRecords.length);
// => a string
console.log(userRecords[0].id);
1const FindManyComponent = () => {
2 const [{data, error, fetching}, refresh] = useFindMany(api.user);
3if (!data) return null;
4
5// => a number
6console.log(data.length)
7
8return <>
9{data.map(record => JSON.stringify(record))}
10
11 </>
12};

Retrieving a single user record by a uniquely identifiable field 

After adding a unique validation to a field, you can retrieve a single record by using the finders generated below. If you would like to edit the fields returned or filtering, see the filtering section.

Retrieving a single user record by id 

Individual user records can be retrieved using the "find many" API endpoint pre-filtered by the field's id. Throws if stored data is not unique.

Find users
const userRecord = await api.user.findById("some-value");
// => a string
console.log(userRecord.id);
1const FindByComponent = () => {
2 const [{data, error, fetching}, refresh] = useFindBy(api.user.findById, "some-value");
3 // => a string
4 console.log(data?.id);
5
6return <>{JSON.stringify(data)}</>;
7}
const userRecord = await api.user.findById("some-value");
// => a string
console.log(userRecord.id);
1const FindByComponent = () => {
2 const [{data, error, fetching}, refresh] = useFindBy(api.user.findById, "some-value");
3 // => a string
4 console.log(data?.id);
5
6return <>{JSON.stringify(data)}</>;
7}

Sorting 

Records can be sorted in the database to retrieve them in a certain order. Records are always implicitly sorted by ID ascending unless an explicit sort on the id field is defined. The GraphQL type UserSort defines which fields can be sorted by.

Records can be sorted by multiple different fields and in multiple different directions by passing a list of UserSort instead of just one.

Pass the sort option to the JS client, or the sort variable to a GraphQL query to sort the records returned.

Sort user by most recently created
const userRecords = await api.user.findMany({ sort: { createdAt: "Descending" } });
const [result, refresh] = useFindMany(api.user, { sort: { createdAt: "Descending" } });
const { data, error, fetching } = result;
1query FindManyUsers($sort: [UserSort!]) {
2 users(sort: $sort) {
3 edges {
4 node {
5 __typename
6 id
7
8 # ...
9
10 createdAt
11 lastSignedIn
12 updatedAt
13 }
14 }
15 }
16}
Variables
json
{ "sort": { "createdAt": "Descending" } }
const userRecords = await api.user.findMany({ sort: { createdAt: "Descending" } });
const [result, refresh] = useFindMany(api.user, { sort: { createdAt: "Descending" } });
const { data, error, fetching } = result;

Sort by multiple fields by passing an array of { [field]: "Ascending" | "Descending" } objects.

Sort user by multiple fields
const userRecords = await api.user.findMany({
sort: [{ id: "Descending" }, { createdAt: "Ascending" }],
});
1const [result, refresh] = useFindMany(api.user, {
2 sort: [
3 { id: "Descending" },
4 { createdAt: "Ascending" }
5 ]
6});
7const { data, error, fetching } = result;
1query FindManyUsers($sort: [UserSort!]) {
2 users(sort: $sort) {
3 edges {
4 node {
5 __typename
6 id
7
8 # ...
9
10 createdAt
11 lastSignedIn
12 updatedAt
13 }
14 }
15 }
16}
Variables
json
{ "sort": [{ "id": "Descending" }, { "createdAt": "Ascending" }] }
const userRecords = await api.user.findMany({
sort: [{ id: "Descending" }, { createdAt: "Ascending" }],
});
1const [result, refresh] = useFindMany(api.user, {
2 sort: [
3 { id: "Descending" },
4 { createdAt: "Ascending" }
5 ]
6});
7const { data, error, fetching } = result;

Available fields for sorting 

You can sort user records by the following fields:

FieldSort type
idAscending / Descending
emailAscending / Descending
lastNameAscending / Descending
firstNameAscending / Descending
lastSignedInAscending / Descending
googleImageUrlAscending / Descending
createdAtAscending / Descending
updatedAtAscending / Descending

For example, you can sort by the id field:

Sort users by id descending
const userRecords = await api.user.findMany({
sort: { id: "Descending" },
});
const [result, refresh] = useFindMany(api.user, {
sort: { id: 'Descending'}
})
const { data, error, fetching } = result;
1query FindManyUsers($sort: [UserSort!]) {
2 users(sort: $sort) {
3 edges {
4 node {
5 __typename
6 id
7
8 # ...
9
10 createdAt
11 lastSignedIn
12 updatedAt
13 }
14 }
15 }
16}
Variables
json
{ "sort": { "id": "Descending" } }
const userRecords = await api.user.findMany({
sort: { id: "Descending" },
});
const [result, refresh] = useFindMany(api.user, {
sort: { id: 'Descending'}
})
const { data, error, fetching } = result;

Read more about sorting in the Sorting and Filtering reference.

Searching 

user records can be searched using Gadget's built in full text search functionality. Gadget search is appropriate for powering autocompletes, searchable tables, or other experiences where humans are writing search queries. It's typo tolerant, synonym aware and supports simple search operators like ! to exclude search terms.

Search Users by passing the search parameter with a search query string.

Search isn't field specific in Gadget -- all String or RichText field types are searched with the built in search functionality.

Full text search Users
const userRecords = await api.user.findMany({
search: "a specific phrase to search for",
});
const [result, refresh] = useFindMany(api.user, {
search: "a specific phrase to search for",
});
const { data, error, fetching } = result;
1query FindManyUsers($search: String) {
2 users(search: $search) {
3 edges {
4 node {
5 __typename
6 id
7
8 # ...
9
10 createdAt
11 lastSignedIn
12 updatedAt
13 }
14 }
15 }
16}
Variables
json
{ "search": "a specific phrase to search for" }
const userRecords = await api.user.findMany({
search: "a specific phrase to search for",
});

Filtering 

user records can be filtered to return only the appropriate records. Records can be filtered on any field, including those managed by Gadget or fields added by developers. Filters can be combined with sorts, searches and paginated using cursor-based Relay pagination.

Filter Users by passing the filter parameter with a filter object. Filter objects are nestable boolean conditions expressed as JS objects capturing a key, an operator, and usually a value.

Find Users created in the last day
const yesterday = new Date(Date.now() - 86400000);
const userRecords = await api.user.findMany({
filter: { createdAt: { greaterThan: yesterday } },
});
const yesterday = new Date(Date.now() - 86400000);
const [result, refresh] = useFindMany(api.user, {
filter: { createdAt: { greaterThan: yesterday }}
})
const { data, error, fetching } = result;
1query FindManyUsers($filter: [UserFilter!]) {
2 users(filter: $filter) {
3 edges {
4 node {
5 __typename
6 id
7
8 # ...
9
10 createdAt
11 lastSignedIn
12 updatedAt
13 }
14 }
15 }
16}
Variables
json
{ "filter": { "createdAt": { "greaterThan": "2024-11-22T23:24:50.817Z" } } }
const yesterday = new Date(Date.now() - 86400000);
const userRecords = await api.user.findMany({
filter: { createdAt: { greaterThan: yesterday } },
});
const yesterday = new Date(Date.now() - 86400000);
const [result, refresh] = useFindMany(api.user, {
filter: { createdAt: { greaterThan: yesterday }}
})
const { data, error, fetching } = result;

Available fields for filtering 

The GraphQL type UserFilter defines which fields can be filtered on.

Field

Filter type

idIDFilter
emailEmailFilter
lastNameStringFilter
firstNameStringFilter
lastSignedInDateTimeFilter
googleImageUrlURLFilter
rolesRoleAssignmentsFilter
createdAtDateTimeFilter
updatedAtDateTimeFilter

For example, we can filter user records on the id field:

const userRecords = await api.user.findMany({
filter: {
id: { isSet: true },
},
});
1const [result, refresh] = useFindMany(api.user, {
2 filter: {
3 id: {isSet: true}
4 }
5})
6const { data, error, fetching } = result;
1query FindManyUsers($filter: [UserFilter!]) {
2 users(filter: $filter) {
3 edges {
4 node {
5 __typename
6 id
7
8 # ...
9
10 createdAt
11 lastSignedIn
12 updatedAt
13 }
14 }
15 }
16}
Variables
json
{ "filter": { "id": { "isSet": true } } }
const userRecords = await api.user.findMany({
filter: {
id: { isSet: true },
},
});
1const [result, refresh] = useFindMany(api.user, {
2 filter: {
3 id: {isSet: true}
4 }
5})
6const { data, error, fetching } = result;

Read more about the available filters in the Sorting and Filtering reference.

Combining filters 

Records can be filtered by multiple different fields simultaneously. If you want to combine filters using boolean logic, nest them under the AND, OR, or NOT keys of a parent filter. Filters can be nested deeply by passing multiple levels boolean condition filters.

You can also pass a list of filters to the filter parameter which will be implicitly ANDed with one another such that they all need to match for a record to be returned.

Users created this week or updated today
1const yesterday = new Date(Date.now() - 86400000);
2const oneWeekAgo = new Date(Date.now() - 604800000);
3const userRecords = await api.user.findMany({
4 filter: {
5 OR: [
6 {
7 createdAt: { greaterThan: oneWeekAgo },
8 },
9 {
10 updatedAt: { greaterThan: yesterday },
11 },
12 ],
13 },
14});
1const yesterday = new Date(Date.now() - 86400000);
2const oneWeekAgo = new Date(Date.now() - 604800000);
3const [result, refresh] = useFindMany(api.user, {
4 filter: {
5 OR: [
6 {
7 createdAt: { greaterThan: oneWeekAgo },
8 },
9 {
10 updatedAt: { greaterThan: yesterday },
11 },
12 ]
13 }
14})
15const { data, error, fetching } = result;
1query FindManyUsers($filter: [UserFilter!]) {
2 users(filter: $filter) {
3 edges {
4 node {
5 __typename
6 id
7
8 # ...
9
10 createdAt
11 lastSignedIn
12 updatedAt
13 }
14 }
15 }
16}
Variables
json
1{
2 "filter": {
3 "OR": [
4 { "createdAt": { "greaterThan": "2024-11-16T23:24:50.817Z" } },
5 { "updatedAt": { "greaterThan": "2024-11-22T23:24:50.817Z" } }
6 ]
7 }
8}
1const yesterday = new Date(Date.now() - 86400000);
2const oneWeekAgo = new Date(Date.now() - 604800000);
3const userRecords = await api.user.findMany({
4 filter: {
5 OR: [
6 {
7 createdAt: { greaterThan: oneWeekAgo },
8 },
9 {
10 updatedAt: { greaterThan: yesterday },
11 },
12 ],
13 },
14});
1const yesterday = new Date(Date.now() - 86400000);
2const oneWeekAgo = new Date(Date.now() - 604800000);
3const [result, refresh] = useFindMany(api.user, {
4 filter: {
5 OR: [
6 {
7 createdAt: { greaterThan: oneWeekAgo },
8 },
9 {
10 updatedAt: { greaterThan: yesterday },
11 },
12 ]
13 }
14})
15const { data, error, fetching } = result;

Pagination 

All Gadget record lists, including the top level user finder as well as associations to user, are structured as GraphQL connections. GraphQL connections are the de facto standard for querying lists and support cursor-based forward and backward pagination. When querying via GraphQL, you must select the edges field and then the node field to get the user record. When querying using a Gadget API client, the GraphQL queries are generated for you and the records are unwrapped and returned as a GadgetRecordList ready for use.

user pagination supports the standard GraphQL connection pagination arguments: first + after, or last + before. Pagination is done using cursors, which you can retrieve from the edge.cursor field or the pageInfo.startCursor properties.

Get the first page of 25 users
const userRecords = await api.user.findMany({ first: 25 });
// => no greater than 25
console.log(userRecords.length);
1const FirstPage = () => {
2 const [{ data, error, fetching }, refresh] = useFindMany(api.user, {first: 25})
3 if (!data) return null;
4
5// => no greater than 25
6console.log(data.length);
7
8return <>
9{data.map(record => JSON.stringify(record))}
10
11 </>
12}
1query FindManyUsers($first: Int, $after: String) {
2 users(first: $first, after: $after) {
3 pageInfo {
4 hasNextPage
5 hasPreviousPage
6 startCursor
7 endCursor
8 }
9 edges {
10 cursor
11 node {
12 __typename
13 id
14
15 # ...
16
17 createdAt
18 lastSignedIn
19 updatedAt
20 }
21 }
22 }
23}
Variables
json
{ "first": 25 }
const userRecords = await api.user.findMany({ first: 25 });
// => no greater than 25
console.log(userRecords.length);
1const FirstPage = () => {
2 const [{ data, error, fetching }, refresh] = useFindMany(api.user, {first: 25})
3 if (!data) return null;
4
5// => no greater than 25
6console.log(data.length);
7
8return <>
9{data.map(record => JSON.stringify(record))}
10
11 </>
12}
Next 25 user records after cursor
const userRecords = await api.user.findMany({ after: "example-cursor", first: 25 });
1const SecondPage = (props) => {
2 const [{ data, error, fetching }, refresh] = useFindMany(api.user, {after: "example-cursor", first: 25});
3 if (!data) return null;
4
5// => no greater than 25
6console.log(data.length);
7
8return <>
9{data.map(record => JSON.stringify(record))}
10
11 </>
12}
1query FindManyUsers($first: Int, $after: String) {
2 users(first: $first, after: $after) {
3 pageInfo {
4 hasNextPage
5 hasPreviousPage
6 startCursor
7 endCursor
8 }
9 edges {
10 cursor
11 node {
12 __typename
13 id
14
15 # ...
16
17 createdAt
18 lastSignedIn
19 updatedAt
20 }
21 }
22 }
23}
Variables
json
{ "first": 25, "after": "abcdefg" }
const userRecords = await api.user.findMany({ after: "example-cursor", first: 25 });
1const SecondPage = (props) => {
2 const [{ data, error, fetching }, refresh] = useFindMany(api.user, {after: "example-cursor", first: 25});
3 if (!data) return null;
4
5// => no greater than 25
6console.log(data.length);
7
8return <>
9{data.map(record => JSON.stringify(record))}
10
11 </>
12}

Pagination Limits 

Root-level record finders like users support a maximum page size of 250 records and a default page size of 50 records. The page size is controlled using the first or last GraphQL field arguments.

Related record finders that access lists of records through a has many or has many through field support a maximum page size of 100 records and a default page size of 50 records.

Get the next or previous page 

When using the generated JavaScript API client, including the api parameter in a Gadget code effect, the record lists returned from findMany calls can be paginated using the nextPage() or previousPage() option.

Both nextPage() and previousPage() will throw an error if the corresponding hasNextPage or hasPreviousPage is false.

JavaScript
1const userRecords = await api.user.findMany();
2if (userRecords.hasNextPage) {
3 const nextPage = await userRecords.nextPage();
4}
5if (userRecords.hasPreviousPage) {
6 const prevPage = await userRecords.previousPage();
7}
1const userRecords = await api.user.findMany();
2if (userRecords.hasNextPage) {
3 const nextPage = await userRecords.nextPage();
4}
5if (userRecords.hasPreviousPage) {
6 const prevPage = await userRecords.previousPage();
7}

When using React and paging through records, you can use cursors to get the previous or next pages of records. This is an example of a React component that pages forward and backward through 2 records at a time for user.

React
1// your Gadget project's API Client
2import { api } from "../api";
3import { useFindMany } from "@gadgetinc/react";
4import { useCallback, useState } from "react";
5
6export default function TestComponent() {
7 // the number of records per page
8 const NUM_ON_PAGE = 2;
9
10 const [cursor, setCursor] = useState({ first: NUM_ON_PAGE });
11 // using Gadget React hooks to fetch records of user
12 const [{ data, fetching, error }] = useFindMany(api.user, {
13 ...cursor,
14 });
15
16 const getNextPage = useCallback(() => {
17 // use first + after to page forwards
18 setCursor({ first: NUM_ON_PAGE, after: data.endCursor });
19 }, [data]);
20
21 const getPreviousPage = useCallback(() => {
22 // use last + before to page backwards
23 setCursor({ last: NUM_ON_PAGE, before: data.startCursor });
24 }, [data]);
25
26 return (
27 <div>
28 <button onClick={getPreviousPage} disabled={!data?.hasPreviousPage}>
29 Previous page
30 </button>
31 <button onClick={getNextPage} disabled={!data?.hasNextPage}>
32 Next page
33 </button>
34 {!fetching && data.map((d) => <div>{d.id}</div>)}
35 </div>
36 );
37}
1// your Gadget project's API Client
2import { api } from "../api";
3import { useFindMany } from "@gadgetinc/react";
4import { useCallback, useState } from "react";
5
6export default function TestComponent() {
7 // the number of records per page
8 const NUM_ON_PAGE = 2;
9
10 const [cursor, setCursor] = useState({ first: NUM_ON_PAGE });
11 // using Gadget React hooks to fetch records of user
12 const [{ data, fetching, error }] = useFindMany(api.user, {
13 ...cursor,
14 });
15
16 const getNextPage = useCallback(() => {
17 // use first + after to page forwards
18 setCursor({ first: NUM_ON_PAGE, after: data.endCursor });
19 }, [data]);
20
21 const getPreviousPage = useCallback(() => {
22 // use last + before to page backwards
23 setCursor({ last: NUM_ON_PAGE, before: data.startCursor });
24 }, [data]);
25
26 return (
27 <div>
28 <button onClick={getPreviousPage} disabled={!data?.hasPreviousPage}>
29 Previous page
30 </button>
31 <button onClick={getNextPage} disabled={!data?.hasNextPage}>
32 Next page
33 </button>
34 {!fetching && data.map((d) => <div>{d.id}</div>)}
35 </div>
36 );
37}

Get all records 

If you need to get all available data for user, you will need to paginate through all pages of data. If you have a large amount of data, this can take a long time. Make sure you need to collect all data at once before writing a pagination loop that reads all records! If you are querying records for display in a UI and cannot display all your records at once, we don't recommend fetching all the data beforehand - instead, use the cursor to read additional data when the user needs it.

If you need all data for analytics applications or to collect some statistics on your data, consider options like intermediate models and pre-defined data rollups.

If you have determined that you need all your data, you can fetch it using cursors and a loop. We also suggest using select so that you only grab fields that are needed, in addition to applying a filter, if possible. Using first with the maximum allowable value will also allow you to grab the maximum number of records you can at once.

Page through all records
JavaScript
1// use allRecords to store all records
2const allRecords = [];
3let records = await api.user.findMany({
4 first: 250,
5 select: {
6 id: true,
7 },
8 filter: {
9 // add filter conditions, if possible
10 },
11});
12
13allRecords.push(...records);
14
15// loop through additional pages to get all protected orders
16while (records.hasNextPage) {
17 // paginate
18 records = await records.nextPage();
19 allRecords.push(...records);
20}
1// use allRecords to store all records
2const allRecords = [];
3let records = await api.user.findMany({
4 first: 250,
5 select: {
6 id: true,
7 },
8 filter: {
9 // add filter conditions, if possible
10 },
11});
12
13allRecords.push(...records);
14
15// loop through additional pages to get all protected orders
16while (records.hasNextPage) {
17 // paginate
18 records = await records.nextPage();
19 allRecords.push(...records);
20}

Selecting fields, and fields of fields 

When using the JavaScript client, all of findOne, maybeFindOne, findMany, findFirst, maybeFindFirst, and various action functions, allow requesting specific fields of a user and its relationships. The select option controls which fields are selected in the generated GraphQL query sent to the Gadget API. Pass each field you want to select in an object, with true as the value for scalar fields, and a nested object of the same shape for nested fields.

Gadget has a default selection that will retrieve all of the scalar fields for a user. If you don't pass a select option to a record finder, this default selection will be used.

Select only some user fields
1// fetch only the id and createdAt field
2const userRecords = await api.user.findMany({
3 select: { id: true, createdAt: true },
4});
5// fetch all the scalar fields for the model, but no relationship fields
6const userRecords = await api.user.findMany();
const SelectionComponent = (props) => {
// fetch only the id and createdAt field
const [{data, error, fetching}, refresh] = useFindMany(api.user, {select: { id: true, createdAt: true }});
// ...
}
1// fetch only the id and createdAt field
2const userRecords = await api.user.findMany({
3 select: { id: true, createdAt: true },
4});
5// fetch all the scalar fields for the model, but no relationship fields
6const userRecords = await api.user.findMany();
const SelectionComponent = (props) => {
// fetch only the id and createdAt field
const [{data, error, fetching}, refresh] = useFindMany(api.user, {select: { id: true, createdAt: true }});
// ...
}

If you want to include the ID of a belongs to or has one relationship in your response, you can add the ID of the relationship field to the select parameter. For example, say we have a ticket model that belongs to a flight model. We can get the flight that the ticket is associated with like so:

Get associated flight ID
JavaScript
const [{ data, fetching, error }, _refetch] = useFindMany(api.ticket, {
select: { id: true, ticketNumber: true, flightId: true },
});
const [{ data, fetching, error }, _refetch] = useFindMany(api.ticket, {
select: { id: true, ticketNumber: true, flightId: true },
});

Where flight is the name of the relationship field on the ticket model. You must append Id in camel case. If flightId is not included in the select statement, it will not be part of the returned object.

Realtime subscriptions with live queries 

Each read function in the user runs once and returns a static set of results. There is also a second mode for subscribing to the results of the query as they change over time.

By passing live: true to any read query or hook, you'll get a stream of results as data changes in the backend, instead of just one result. This is useful for automatically updating your UI when any record is created, updated, or deleted in your backend database.

Realtime queries are issued by passing live: true to your API call or React hook. For example, you can query and stream changes to the record with id 123:

Fetch user 123 in live mode
// calling findOne with live: true will return a stream of results as an AsyncIterator, not just one result
for await (const record of api.user.findOne("123", { live: true })) {
// record will be a GadgetRecord object
console.log("new record version", record);
}
1export const Record123 = (props) => {
2 const [{data, error, fetching}] = useFindOne(api.user,
3 "123", // the id of the record to fetch
4 {
5 // make this a realtime live query
6 live: true,
7 });
8 if (!data) return null;
9 return (
10 <div>
11 Record 123 last updated at {data.updatedAt}
12 </div>
13 );
14}
// calling findOne with live: true will return a stream of results as an AsyncIterator, not just one result
for await (const record of api.user.findOne("123", { live: true })) {
// record will be a GadgetRecord object
console.log("new record version", record);
}
1export const Record123 = (props) => {
2 const [{data, error, fetching}] = useFindOne(api.user,
3 "123", // the id of the record to fetch
4 {
5 // make this a realtime live query
6 live: true,
7 });
8 if (!data) return null;
9 return (
10 <div>
11 Record 123 last updated at {data.updatedAt}
12 </div>
13 );
14}

You can also subscribe to realtime results for pages of records. For example, we can fetch and render a list of the first ten user records, which will automatically update when backend data changes:

First 10 user records in live mode
// calling findMany with live: true will return a stream of results as an AsyncIterator, not just one result
for await (const list of api.user.findMany({ live: true, first: 10 })) {
// list will be an array of GadgetRecord objects
console.log("new query result", list);
}
1export const FirstPage = (props) => {
2 const [{data, error, fetching}] = useFindMany(api.user, {
3 // make this a realtime live query
4 live: true,
5 first: 10
6 });
7 if (!data) return null;
8 return (
9 <div>
10 {data.map((record) => (
11 <div key={record.id}>{record.id}</div>
12 ))}
13 </div>
14 );
15}
// calling findMany with live: true will return a stream of results as an AsyncIterator, not just one result
for await (const list of api.user.findMany({ live: true, first: 10 })) {
// list will be an array of GadgetRecord objects
console.log("new query result", list);
}
1export const FirstPage = (props) => {
2 const [{data, error, fetching}] = useFindMany(api.user, {
3 // make this a realtime live query
4 live: true,
5 first: 10
6 });
7 if (!data) return null;
8 return (
9 <div>
10 {data.map((record) => (
11 <div key={record.id}>{record.id}</div>
12 ))}
13 </div>
14 );
15}

For more information, see the Realtime Queries guide.

Type Safety 

The select option is fully type-safe if you're using TypeScript. The returned GadgetRecord type will have a <Shape> exactly matching the fields and nested fields you selected.

This behavior of selecting only some fields is built right into GraphQL. If you want to limit or expand what you retrieve from a GraphQL query, include or exclude those fields in your GraphQL query. For more information on executing GraphQL queries, see GraphQL.

Select nested user fields
1// fetch the id and createdAt field, and fetch some nested fields from an example relationship field named `someRelatedObject`
2const userRecords = await api.user.findMany({
3 select: {
4 id: true,
5 createdAt: true,
6 someRelatedObject: { id: true, createdAt: true },
7 },
8});
const SelectionComponent = (props) => {
// fetch the id and createdAt field, and fetch some nested fields from an example relationship field named `someRelatedObject`
const [{data, error, fetching}, refresh] = useFindMany(api.user, {select: { id: true, createdAt: true, someRelatedObject: { id: true, createdAt: true } }});
// ...
}
1// fetch the id and createdAt field, and fetch some nested fields from an example relationship field named `someRelatedObject`
2const userRecords = await api.user.findMany({
3 select: {
4 id: true,
5 createdAt: true,
6 someRelatedObject: { id: true, createdAt: true },
7 },
8});
const SelectionComponent = (props) => {
// fetch the id and createdAt field, and fetch some nested fields from an example relationship field named `someRelatedObject`
const [{data, error, fetching}, refresh] = useFindMany(api.user, {select: { id: true, createdAt: true, someRelatedObject: { id: true, createdAt: true } }});
// ...
}

Combining parameters 

Sort, search, filtering, selection, and pagination parameters can be combined to access the exact set of records needed for your use case.

Combining Parameters
1const userRecords = await api.user.findMany({
2 search: "<some search query>",
3 sort: { createdAt: "Descending" },
4 filter: { updatedAt: { greaterThan: new Date(Date.now() - 86400000) } },
5 select: { id: true, createdAt: true },
6 first: 25,
7 after: "abcdefg",
8});
1const [result, refresh] = useFindMany(api.user, {
2 search: "<some search query>",
3 sort: { createdAt: "Descending" },
4 filter: { updatedAt: { greaterThan: new Date(Date.now() - 86400000)}},
5 select: { id: true, createdAt: true },
6 first: 25,
7 after: "abcdefg"
8});
9const { data, error, fetching } = result;
1query FindManyUsers(
2 $after: String
3 $before: String
4 $first: Int
5 $last: Int
6 $search: String
7 $sort: [UserSort!]
8 $filter: [UserFilter!]
9) {
10 users(
11 after: $after
12 before: $before
13 first: $first
14 last: $last
15 search: $search
16 sort: $sort
17 filter: $filter
18 ) {
19 edges {
20 node {
21 __typename
22 id
23
24 # ...
25
26 createdAt
27 email
28 firstName
29 googleImageUrl
30 lastName
31 lastSignedIn
32 roles {
33 key
34 name
35 }
36 updatedAt
37 }
38 }
39 }
40}
Variables
json
1{
2 "search": "<some search query>",
3 "sort": { "createdAt": "Descending" },
4 "filter": { "updatedAt": { "greaterThan": "2024-11-22T23:24:50.963Z" } },
5 "first": 25,
6 "after": "abcdefg"
7}
1const userRecords = await api.user.findMany({
2 search: "<some search query>",
3 sort: { createdAt: "Descending" },
4 filter: { updatedAt: { greaterThan: new Date(Date.now() - 86400000) } },
5 select: { id: true, createdAt: true },
6 first: 25,
7 after: "abcdefg",
8});
1const [result, refresh] = useFindMany(api.user, {
2 search: "<some search query>",
3 sort: { createdAt: "Descending" },
4 filter: { updatedAt: { greaterThan: new Date(Date.now() - 86400000)}},
5 select: { id: true, createdAt: true },
6 first: 25,
7 after: "abcdefg"
8});
9const { data, error, fetching } = result;

Invoking Actions 

user records are changed by invoking Actions. Actions are the things that "do" stuff -- update records, make API calls, call backend code, etc. Actions with a GraphQL API trigger each have one corresponding GraphQL mutation and a corresponding function available in the API client libraries. Nested Actions can also be invoked with the API client, by providing the actions as input to any relationship fields.

Action Result format 

Each API action returns results in the same format that includes a success indicator, errors, and the actual result if the action succeeded. The result is the record that was acted on for a model action, or a list of records for a bulk action, or a JSON blob for Global Actions. Model actions that delete the record don't return the record.

The success field returns a boolean indicating if the action executed as expected. Any execution errors are returned in the errors object, which will always be null if success is true or contain ExecutionError objects if success is false.

ExecutionError objects always have a message describing what error prevented the action from succeeding, as well as a code attribute that gives a stable, searchable, human-readable error class code for referencing this specific error. Details on each error code can be found in the Errors documentation. All ExecutionError object types returned by the GraphQL object can be one of many types of error, where some types have extra data that is useful for remedying the error. All error types will always have message and code properties, but some, like InvalidRecordError have extra fields for use by clients.

Errors when using the generated client 

The generated JavaScript client automatically interprets errors from invoking actions and throws JavaScript Error instances if the action didn't succeed. The Error objects it throws are rich, and expose extra error properties beyond just message and code if they exist.

Errors thrown by the JavaScript client are easiest to catch by using a try/catch statement around an await, like so:

JavaScript
1import {
2 GadgetOperationError,
3 InvalidRecordError,
4} from "@gadgetinc/api-client-core";
5
6// must be in an async function to use await` syntax
7export async function run({ api }) {
8 try {
9 return await api.exampleModel.create({ name: "example record name" });
10 } catch (error) {
11 if (error instanceof GadgetOperationError) {
12 // a recognized general error has occurred, retry the operation or inspect \error.code\`
13 console.error(error);
14 } else if (error instanceof InvalidRecordError) {
15 // the submitted input data for the action was invalid, inspect the invalid fields which \`InvalidRecordError\` exposes
16 console.error(error.validationErrors);
17 } else {
18 // an unrecognized error occurred like an HTTP connection interrupted error or a syntax error. Re-throw it because it's not clear what to do to fix it
19 throw error;
20 }
21 }
22}
1import {
2 GadgetOperationError,
3 InvalidRecordError,
4} from "@gadgetinc/api-client-core";
5
6// must be in an async function to use await` syntax
7export async function run({ api }) {
8 try {
9 return await api.exampleModel.create({ name: "example record name" });
10 } catch (error) {
11 if (error instanceof GadgetOperationError) {
12 // a recognized general error has occurred, retry the operation or inspect \error.code\`
13 console.error(error);
14 } else if (error instanceof InvalidRecordError) {
15 // the submitted input data for the action was invalid, inspect the invalid fields which \`InvalidRecordError\` exposes
16 console.error(error.validationErrors);
17 } else {
18 // an unrecognized error occurred like an HTTP connection interrupted error or a syntax error. Re-throw it because it's not clear what to do to fix it
19 throw error;
20 }
21 }
22}

For more information on error codes, consult the Errors documentation.

user signOut 

Input 

signOut operates on one user in particular, identified by the id variable.signOut accepts the following input parameters:

signOut Input Data
1export type SignOutUserInput = {
2
3 lastSignedIn?: Date | Scalars['ISO8601DateString'] | null;
4
5 lastName?: (Scalars['String'] | null) | null;
6
7 email?: (Scalars['String'] | null) | null;
8
9 googleImageUrl?: (Scalars['String'] | null) | null;
10
11 firstName?: (Scalars['String'] | null) | null;
12};
13
14
15
16export type SignOutUserArguments = {
17
18 user?: SignOutUserInput | null;
19};
1input SignOutUserInput {
2 lastSignedIn: DateTime
3 lastName: String
4 email: String
5 googleImageUrl: String
6 firstName: String
7}
8
9input SignOutUserArguments {
10 user: SignOutUserInput
11}
Example signOut Invocation
1const userRecord = await api.user.signOut("123", {
2 email: "[email protected]",
3 googleImageUrl: "https://example.com",
4 lastName: "example value for lastName",
5 lastSignedIn: "2024-11-01T00:00:00.000+00:00",
6 roles: ["signed-in"],
7});
1const ExampleRunSignOutComponent = (props) => {
2 const [{ data, error, fetching }, signOut] = useAction(api.user.signOut);
3
4 return (
5 <>
6 <button
7 onClick={async () => {
8 await signOut({
9 email: "[email protected]",
10 googleImageUrl: "https://example.com",
11 id: "123",
12 lastName: "example value for lastName",
13 lastSignedIn: "2024-11-01T00:00:00.000+00:00",
14 roles: ["signed-in"],
15 });
16 }}
17 >
18 Run Action
19 </button>
20 Result: {JSON.stringify(data)}
21 </>
22 );
23};
1mutation SignOutUser($user: SignOutUserInput, $id: GadgetID!) {
2 signOutUser(user: $user, id: $id) {
3 success
4 errors {
5 message
6 ... on InvalidRecordError {
7 validationErrors {
8 apiIdentifier
9 message
10 }
11 record
12 model {
13 apiIdentifier
14 }
15 }
16 }
17 user {
18 __typename
19 id
20 createdAt
21 email
22 firstName
23 googleImageUrl
24 lastName
25 lastSignedIn
26 roles {
27 key
28 name
29 }
30 updatedAt
31 }
32 }
33}
Variables
json
1{
2 "user": {
3 "email": "[email protected]",
4 "googleImageUrl": "https://example.com",
5 "lastName": "example value for lastName",
6 "lastSignedIn": "2024-11-01T00:00:00.000+00:00",
7 "roles": ["signed-in"]
8 },
9 "id": "123"
10}
1const userRecord = await api.user.signOut("123", {
2 email: "[email protected]",
3 googleImageUrl: "https://example.com",
4 lastName: "example value for lastName",
5 lastSignedIn: "2024-11-01T00:00:00.000+00:00",
6 roles: ["signed-in"],
7});
1const ExampleRunSignOutComponent = (props) => {
2 const [{ data, error, fetching }, signOut] = useAction(api.user.signOut);
3
4 return (
5 <>
6 <button
7 onClick={async () => {
8 await signOut({
9 email: "[email protected]",
10 googleImageUrl: "https://example.com",
11 id: "123",
12 lastName: "example value for lastName",
13 lastSignedIn: "2024-11-01T00:00:00.000+00:00",
14 roles: ["signed-in"],
15 });
16 }}
17 >
18 Run Action
19 </button>
20 Result: {JSON.stringify(data)}
21 </>
22 );
23};
Output 

signOut returns the user. In the JS client, the fields returned can be controlled with the select option. In GraphQL, the return format is the action result format, which includes the record if the action was successful. You can include or exclude the fields you need right in the mutation itself.

signOut Output Data
GraphQL
1type SignOutUserResult {
2 success: Boolean!
3 errors: [ExecutionError!]
4 actionRun: String
5 user: User
6}

user update 

Input 

update operates on one user in particular, identified by the id variable.update accepts the following input parameters:

update Input Data
1export type UpdateUserInput = {
2
3 lastSignedIn?: Date | Scalars['ISO8601DateString'] | null;
4
5 lastName?: (Scalars['String'] | null) | null;
6
7 email?: (Scalars['String'] | null) | null;
8
9 googleImageUrl?: (Scalars['String'] | null) | null;
10
11 firstName?: (Scalars['String'] | null) | null;
12};
13
14
15
16export type UpdateUserArguments = {
17
18 user?: UpdateUserInput | null;
19};
1input UpdateUserInput {
2 lastSignedIn: DateTime
3 lastName: String
4 email: String
5 googleImageUrl: String
6 firstName: String
7}
8
9input UpdateUserArguments {
10 user: UpdateUserInput
11}
Example update Invocation
1const userRecord = await api.user.update("123", {
2 email: "[email protected]",
3 googleImageUrl: "https://example.com",
4 lastName: "example value for lastName",
5 lastSignedIn: "2024-11-01T00:00:00.000+00:00",
6 roles: ["signed-in"],
7});
1const ExampleRunUpdateComponent = (props) => {
2 const [{ data, error, fetching }, update] = useAction(api.user.update);
3
4 return (
5 <>
6 <button
7 onClick={async () => {
8 await update({
9 email: "[email protected]",
10 googleImageUrl: "https://example.com",
11 id: "123",
12 lastName: "example value for lastName",
13 lastSignedIn: "2024-11-01T00:00:00.000+00:00",
14 roles: ["signed-in"],
15 });
16 }}
17 >
18 Run Action
19 </button>
20 Result: {JSON.stringify(data)}
21 </>
22 );
23};
1mutation UpdateUser($user: UpdateUserInput, $id: GadgetID!) {
2 updateUser(user: $user, id: $id) {
3 success
4 errors {
5 message
6 ... on InvalidRecordError {
7 validationErrors {
8 apiIdentifier
9 message
10 }
11 record
12 model {
13 apiIdentifier
14 }
15 }
16 }
17 user {
18 __typename
19 id
20 createdAt
21 email
22 firstName
23 googleImageUrl
24 lastName
25 lastSignedIn
26 roles {
27 key
28 name
29 }
30 updatedAt
31 }
32 }
33}
Variables
json
1{
2 "user": {
3 "email": "[email protected]",
4 "googleImageUrl": "https://example.com",
5 "lastName": "example value for lastName",
6 "lastSignedIn": "2024-11-01T00:00:00.000+00:00",
7 "roles": ["signed-in"]
8 },
9 "id": "123"
10}
1const userRecord = await api.user.update("123", {
2 email: "[email protected]",
3 googleImageUrl: "https://example.com",
4 lastName: "example value for lastName",
5 lastSignedIn: "2024-11-01T00:00:00.000+00:00",
6 roles: ["signed-in"],
7});
1const ExampleRunUpdateComponent = (props) => {
2 const [{ data, error, fetching }, update] = useAction(api.user.update);
3
4 return (
5 <>
6 <button
7 onClick={async () => {
8 await update({
9 email: "[email protected]",
10 googleImageUrl: "https://example.com",
11 id: "123",
12 lastName: "example value for lastName",
13 lastSignedIn: "2024-11-01T00:00:00.000+00:00",
14 roles: ["signed-in"],
15 });
16 }}
17 >
18 Run Action
19 </button>
20 Result: {JSON.stringify(data)}
21 </>
22 );
23};
Output 

update returns the user. In the JS client, the fields returned can be controlled with the select option. In GraphQL, the return format is the action result format, which includes the record if the action was successful. You can include or exclude the fields you need right in the mutation itself.

update Output Data
GraphQL
1type UpdateUserResult {
2 success: Boolean!
3 errors: [ExecutionError!]
4 actionRun: String
5 user: User
6}

user delete 

The delete action destroys the record.

Input 

delete operates on one user in particular, identified by the id variable.

Example delete Invocation
await api.user.delete("123");
1const ExampleRunDeleteComponent = (props) => {
2 const [{ data, error, fetching }, _delete] = useAction(api.user.delete);
3
4 return (
5 <>
6 <button
7 onClick={async () => {
8 await _delete({
9 id: "123",
10 });
11 }}
12 >
13 Run Action
14 </button>
15 Result: {JSON.stringify(data)}
16 </>
17 );
18};
1mutation DeleteUser($id: GadgetID!) {
2 deleteUser(id: $id) {
3 success
4 errors {
5 message
6 ... on InvalidRecordError {
7 validationErrors {
8 apiIdentifier
9 message
10 }
11 record
12 model {
13 apiIdentifier
14 }
15 }
16 }
17 }
18}
Variables
json
{ "id": "123" }
await api.user.delete("123");
1const ExampleRunDeleteComponent = (props) => {
2 const [{ data, error, fetching }, _delete] = useAction(api.user.delete);
3
4 return (
5 <>
6 <button
7 onClick={async () => {
8 await _delete({
9 id: "123",
10 });
11 }}
12 >
13 Run Action
14 </button>
15 Result: {JSON.stringify(data)}
16 </>
17 );
18};
Output 

delete deletes the record, so it returns void in the JS client. In GraphQL it returns only the success and errors from the action result format.

delete Output Data
GraphQL
type DeleteUserResult {
success: Boolean!
errors: [ExecutionError!]
actionRun: String
}

Bulk Actions 

You can run the same action for an array of inputs all at once with bulk actions. Bulk Actions are executed as a single API call and offer better performance when running the same action on many records.

Creates, updates, deletes, and custom actions can all be run in bulk. Bulk Actions repeat the same action each time across a variety of different records. If you want to call different actions, you can't use Bulk Actions and must instead make multiple API calls.

If a bulk action group fails on some of the individual records, the remaining records will still be processed, and the list of errors will be returned in the result. Only the records which succeed in executing the action will be returned in the result.

Bulk user signOut 

Input 

bulkSignOutUsers operates on a set of users, identified by the ids variable.

Example bulkSignOutUsers Invocation
1const userRecords = await api.user.bulkSignOut([
2 {
3 id: "123",
4 lastSignedIn: "2024-11-01T00:00:00.000+00:00",
5 roles: ["signed-in"],
6 },
7 {
8 id: "456",
9 lastSignedIn: "2024-11-01T00:00:00.000+00:00",
10 roles: ["signed-in"],
11 },
12]);
1const RunActionComponent = (props) => {
2 const [{ data, error, fetching }, bulkSignOut] = useBulkAction(api.user.bulkSignOut);
3
4 return (
5 <>
6 <button
7 onClick={async () => {
8 await bulkSignOut([
9 {
10 id: "123",
11 lastSignedIn: "2024-11-01T00:00:00.000+00:00",
12 roles: ["signed-in"],
13 },
14 {
15 id: "456",
16 lastSignedIn: "2024-11-01T00:00:00.000+00:00",
17 roles: ["signed-in"],
18 },
19 ]);
20 console.log(data?.length); //=> a number
21 console.log(data?.[0].id); //=> a string
22 }}
23 >
24 Run Action
25 </button>
26 Result: {JSON.stringify(data)}
27 </>
28 );
29};
1mutation BulkSignOutUsers($inputs: [BulkSignOutUsersInput!]!) {
2 bulkSignOutUsers(inputs: $inputs) {
3 success
4 errors {
5 message
6 }
7 users {
8 id
9 createdAt
10 email
11 firstName
12 googleImageUrl
13 lastName
14 lastSignedIn
15 roles {
16 key
17 name
18 }
19 updatedAt
20 }
21 }
22}
Variables
json
1{
2 "inputs": [
3 {
4 "user": {
5 "lastSignedIn": "2024-11-01T00:00:00.000+00:00",
6 "roles": ["signed-in"]
7 },
8 "id": "123"
9 },
10 {
11 "user": {
12 "lastSignedIn": "2024-11-01T00:00:00.000+00:00",
13 "roles": ["signed-in"]
14 },
15 "id": "456"
16 }
17 ]
18}
1const userRecords = await api.user.bulkSignOut([
2 {
3 id: "123",
4 lastSignedIn: "2024-11-01T00:00:00.000+00:00",
5 roles: ["signed-in"],
6 },
7 {
8 id: "456",
9 lastSignedIn: "2024-11-01T00:00:00.000+00:00",
10 roles: ["signed-in"],
11 },
12]);
1const RunActionComponent = (props) => {
2 const [{ data, error, fetching }, bulkSignOut] = useBulkAction(api.user.bulkSignOut);
3
4 return (
5 <>
6 <button
7 onClick={async () => {
8 await bulkSignOut([
9 {
10 id: "123",
11 lastSignedIn: "2024-11-01T00:00:00.000+00:00",
12 roles: ["signed-in"],
13 },
14 {
15 id: "456",
16 lastSignedIn: "2024-11-01T00:00:00.000+00:00",
17 roles: ["signed-in"],
18 },
19 ]);
20 console.log(data?.length); //=> a number
21 console.log(data?.[0].id); //=> a string
22 }}
23 >
24 Run Action
25 </button>
26 Result: {JSON.stringify(data)}
27 </>
28 );
29};
Output 

bulkSignOutUsers returns the set of users that successfully completed the action. In the JS client, the fields returned for the record can be controlled with the select option. In GraphQL, the response is in the action result format, which includes a selection that completed the action successfully.The success property will be false if any of the records failed to perform their action and the returned set of users will only include the ones that completed successfully.

bulkSignOutUsers Output Data
GraphQL
1"""
2The output when running the signOut on the user model in bulk.
3"""
4type BulkSignOutUsersResult {
5 """
6 Boolean describing if all the bulk actions succeeded or not
7 """
8 success: Boolean!
9
10 """
11 Aggregated list of errors that any bulk action encountered while processing
12 """
13 errors: [ExecutionError!]
14
15 """
16 The list of all changed user records by each sent bulk action. Returned in the same order as the input bulk action params.
17 """
18 users: [User]
19}

Bulk user update 

Input 

bulkUpdateUsers operates on a set of users, identified by the ids variable.

Example bulkUpdateUsers Invocation
1const userRecords = await api.user.bulkUpdate([
2 {
3 id: "123",
4 lastSignedIn: "2024-11-01T00:00:00.000+00:00",
5 roles: ["signed-in"],
6 },
7 {
8 id: "456",
9 lastSignedIn: "2024-11-01T00:00:00.000+00:00",
10 roles: ["signed-in"],
11 },
12]);
1const RunActionComponent = (props) => {
2 const [{ data, error, fetching }, bulkUpdate] = useBulkAction(api.user.bulkUpdate);
3
4 return (
5 <>
6 <button
7 onClick={async () => {
8 await bulkUpdate([
9 {
10 id: "123",
11 lastSignedIn: "2024-11-01T00:00:00.000+00:00",
12 roles: ["signed-in"],
13 },
14 {
15 id: "456",
16 lastSignedIn: "2024-11-01T00:00:00.000+00:00",
17 roles: ["signed-in"],
18 },
19 ]);
20 console.log(data?.length); //=> a number
21 console.log(data?.[0].id); //=> a string
22 }}
23 >
24 Run Action
25 </button>
26 Result: {JSON.stringify(data)}
27 </>
28 );
29};
1mutation BulkUpdateUsers($inputs: [BulkUpdateUsersInput!]!) {
2 bulkUpdateUsers(inputs: $inputs) {
3 success
4 errors {
5 message
6 }
7 users {
8 id
9 createdAt
10 email
11 firstName
12 googleImageUrl
13 lastName
14 lastSignedIn
15 roles {
16 key
17 name
18 }
19 updatedAt
20 }
21 }
22}
Variables
json
1{
2 "inputs": [
3 {
4 "user": {
5 "lastSignedIn": "2024-11-01T00:00:00.000+00:00",
6 "roles": ["signed-in"]
7 },
8 "id": "123"
9 },
10 {
11 "user": {
12 "lastSignedIn": "2024-11-01T00:00:00.000+00:00",
13 "roles": ["signed-in"]
14 },
15 "id": "456"
16 }
17 ]
18}
1const userRecords = await api.user.bulkUpdate([
2 {
3 id: "123",
4 lastSignedIn: "2024-11-01T00:00:00.000+00:00",
5 roles: ["signed-in"],
6 },
7 {
8 id: "456",
9 lastSignedIn: "2024-11-01T00:00:00.000+00:00",
10 roles: ["signed-in"],
11 },
12]);
1const RunActionComponent = (props) => {
2 const [{ data, error, fetching }, bulkUpdate] = useBulkAction(api.user.bulkUpdate);
3
4 return (
5 <>
6 <button
7 onClick={async () => {
8 await bulkUpdate([
9 {
10 id: "123",
11 lastSignedIn: "2024-11-01T00:00:00.000+00:00",
12 roles: ["signed-in"],
13 },
14 {
15 id: "456",
16 lastSignedIn: "2024-11-01T00:00:00.000+00:00",
17 roles: ["signed-in"],
18 },
19 ]);
20 console.log(data?.length); //=> a number
21 console.log(data?.[0].id); //=> a string
22 }}
23 >
24 Run Action
25 </button>
26 Result: {JSON.stringify(data)}
27 </>
28 );
29};
Output 

bulkUpdateUsers returns the set of users that successfully completed the action. In the JS client, the fields returned for the record can be controlled with the select option. In GraphQL, the response is in the action result format, which includes a selection that completed the action successfully.The success property will be false if any of the records failed to perform their action and the returned set of users will only include the ones that completed successfully.

bulkUpdateUsers Output Data
GraphQL
1"""
2The output when running the update on the user model in bulk.
3"""
4type BulkUpdateUsersResult {
5 """
6 Boolean describing if all the bulk actions succeeded or not
7 """
8 success: Boolean!
9
10 """
11 Aggregated list of errors that any bulk action encountered while processing
12 """
13 errors: [ExecutionError!]
14
15 """
16 The list of all changed user records by each sent bulk action. Returned in the same order as the input bulk action params.
17 """
18 users: [User]
19}

Bulk user delete 

bulkDeleteUsers action destroys the records.

Input 

bulkDeleteUsers operates on a set of users, identified by the ids variable.

Example bulkDeleteUsers Invocation
await api.user.bulkDelete(["123", "456"]);
1const RunActionComponent = (props) => {
2 const [{ data, error, fetching }, bulkDelete] = useBulkAction(api.user.bulkDelete);
3
4 return (
5 <>
6 <button
7 onClick={async () => {
8 await bulkDelete({
9 ids: ["123", "456"],
10 });
11 }}
12 >
13 Run Action
14 </button>
15 Result: {JSON.stringify(data)}
16 </>
17 );
18};
1mutation BulkDeleteUsers($ids: [GadgetID!]!) {
2 bulkDeleteUsers(ids: $ids) {
3 success
4 errors {
5 message
6 }
7 }
8}
Variables
json
{ "ids": ["123", "456"] }
await api.user.bulkDelete(["123", "456"]);
1const RunActionComponent = (props) => {
2 const [{ data, error, fetching }, bulkDelete] = useBulkAction(api.user.bulkDelete);
3
4 return (
5 <>
6 <button
7 onClick={async () => {
8 await bulkDelete({
9 ids: ["123", "456"],
10 });
11 }}
12 >
13 Run Action
14 </button>
15 Result: {JSON.stringify(data)}
16 </>
17 );
18};
Output 

bulkDeleteUsers deletes the record, so it returns void in the JS client. In GraphQL it returns only the success and errors from the action result format.

bulkDeleteUsers Output Data
GraphQL
1"""
2The output when running the delete on the user model in bulk.
3"""
4type BulkDeleteUsersResult {
5 """
6 Boolean describing if all the bulk actions succeeded or not
7 """
8 success: Boolean!
9
10 """
11 Aggregated list of errors that any bulk action encountered while processing
12 """
13 errors: [ExecutionError!]
14}

Was this page helpful?