Quiz

This page documents the Quiz model.

Data Shape

Gadget's database stores Quiz 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 Quiz:

Quiz Schema
1export interface Quiz {
2 __typename: "Quiz";
3
4 /** The globally unique, unchanging identifier for this record. Assigned and managed by Gadget. */
5 id: Scalars["GadgetID"];
6
7 /** The time at which this record was first created. Set once upon record creation and never changed. Managed by Gadget. */
8 createdAt: Scalars["DateTime"];
9
10 /** The time at which this record was last changed. Set each time the record is successfully acted upon by an action. Managed by Gadget. */
11 updatedAt: Scalars["DateTime"];
12
13 /** The current state this record is in. Changed by invoking actions. Managed by Gadget. */
14 state: Scalars["RecordState"];
15
16 title: Scalars["String"];
17
18 body: Scalars["String"] | null;
19
20 responses: ResponseConnection;
21
22 results: ResultConnection;
23
24 questions: QuestionConnection;
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: Scalars["JSONObject"];
28}
1type Quiz {
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
17 """
18 The current state this record is in. Changed by invoking actions. Managed by Gadget.
19 """
20 state: RecordState!
21 title: String!
22 body: String
23 responses(
24 """
25 Returns the items in the list that come after the specified cursor.
26 """
27 after: String
28
29 """
30 Returns the first n items from the list.
31 """
32 first: Int
33
34 """
35 Returns the items in the list that come before the specified cursor.
36 """
37 before: String
38
39 """
40 Returns the last n items from the list.
41 """
42 last: Int
43
44 """
45 A list of sort orders to return the results in
46 """
47 sort: [ResponseSort!]
48
49 """
50 A list of filters to refine the results by
51 """
52 filter: [ResponseFilter!]
53
54 """
55 A free form text search query to find records matching
56 """
57 search: String
58 ): ResponseConnection!
59 results(
60 """
61 Returns the items in the list that come after the specified cursor.
62 """
63 after: String
64
65 """
66 Returns the first n items from the list.
67 """
68 first: Int
69
70 """
71 Returns the items in the list that come before the specified cursor.
72 """
73 before: String
74
75 """
76 Returns the last n items from the list.
77 """
78 last: Int
79
80 """
81 A list of sort orders to return the results in
82 """
83 sort: [ResultSort!]
84
85 """
86 A list of filters to refine the results by
87 """
88 filter: [ResultFilter!]
89
90 """
91 A free form text search query to find records matching
92 """
93 search: String
94 ): ResultConnection!
95 questions(
96 """
97 Returns the items in the list that come after the specified cursor.
98 """
99 after: String
100
101 """
102 Returns the first n items from the list.
103 """
104 first: Int
105
106 """
107 Returns the items in the list that come before the specified cursor.
108 """
109 before: String
110
111 """
112 Returns the last n items from the list.
113 """
114 last: Int
115
116 """
117 A list of sort orders to return the results in
118 """
119 sort: [QuestionSort!]
120
121 """
122 A list of filters to refine the results by
123 """
124 filter: [QuestionFilter!]
125
126 """
127 A free form text search query to find records matching
128 """
129 search: String
130 ): QuestionConnection!
131
132 """
133 Get all the fields for this record. Useful for not having to list out all the fields you want to retrieve, but slower.
134 """
135 _all: JSONObject!
136}

You can preview what a real record's shape looks like by fetching it using the alida-quiz-app-2 API Playground.

Any fetched Quiz record will have this same Quiz 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 Quiz record

Individual Quiz 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 Quiz
const quizRecord = await api.quiz.findOne("some-id");
console.log(quizRecord.id); //=> a string
console.log(quizRecord.createdAt); //=> a Date object
const [result, refresh] = useFindOne(api.quiz, "some-id");
const { data, error, fetching } = result;
console.log(data?.id); //=> a string
console.log(data?.createdAt); //=> a Date object
1query GetOneQuiz($id: GadgetID!) {
2 quiz(id: $id) {
3 __typename
4 id
5 state
6 body
7 createdAt
8 questions {
9 edges {
10 node {
11 id
12 state
13 body
14 createdAt
15 imageUrl
16 quiz {
17 id
18 state
19 body
20 createdAt
21 title
22 updatedAt
23 }
24 required
25 sequence
26 title
27 updatedAt
28 }
29 }
30 }
31 responses {
32 edges {
33 node {
34 id
35 state
36 conversionState
37 createdAt
38 email
39 quiz {
40 id
41 state
42 body
43 createdAt
44 title
45 updatedAt
46 }
47 result {
48 id
49 state
50 body
51 createdAt
52 imageUrl
53 updatedAt
54 }
55 updatedAt
56 }
57 }
58 }
59 results {
60 edges {
61 node {
62 id
63 state
64 body
65 createdAt
66 imageUrl
67 productSuggestion {
68 id
69 state
70 barcode
71 compareAtPrice
72 createdAt
73 fulfillmentService
74 grams
75 inventoryManagement
76 inventoryPolicy
77 inventoryQuantity
78 inventoryQuantityAdjustment
79 oldInventoryQuantity
80 option1
81 option2
82 option3
83 position
84 presentmentPrices
85 price
86 requiresShipping
87 shopifyCreatedAt
88 shopifyUpdatedAt
89 sku
90 taxCode
91 taxable
92 title
93 updatedAt
94 weight
95 weightUnit
96 }
97 quiz {
98 id
99 state
100 body
101 createdAt
102 title
103 updatedAt
104 }
105 updatedAt
106 }
107 }
108 }
109 title
110 updatedAt
111 }
112}
Variables
json
{
"id": "some-id"
}

Retrieving the first of many Quiz 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 one Quiz
const quizRecord = await api.quiz.findFirst();
console.log(quizRecord.id); //=> a string
console.log(quizRecord.createdAt); //=> a Date object
const [result, refresh] = useFindFirst(api.quiz);
const { data, error, fetching } = result;
console.log(data?.id); //=> a string
console.log(data?.createdAt); //=> a Date object
1query FindManyQuizzes(
2 $first: Int
3 $search: String
4 $sort: [QuizSort!]
5 $filter: [QuizFilter!]
6) {
7 quizzes(first: $first, search: $search, sort: $sort, filter: $filter) {
8 edges {
9 node {
10 __typename
11 id
12 state
13 body
14 createdAt
15 questions {
16 edges {
17 node {
18 id
19 state
20 body
21 createdAt
22 imageUrl
23 quiz {
24 id
25 state
26 body
27 createdAt
28 title
29 updatedAt
30 }
31 required
32 sequence
33 title
34 updatedAt
35 }
36 }
37 }
38 responses {
39 edges {
40 node {
41 id
42 state
43 conversionState
44 createdAt
45 email
46 quiz {
47 id
48 state
49 body
50 createdAt
51 title
52 updatedAt
53 }
54 result {
55 id
56 state
57 body
58 createdAt
59 imageUrl
60 updatedAt
61 }
62 updatedAt
63 }
64 }
65 }
66 results {
67 edges {
68 node {
69 id
70 state
71 body
72 createdAt
73 imageUrl
74 productSuggestion {
75 id
76 state
77 barcode
78 compareAtPrice
79 createdAt
80 fulfillmentService
81 grams
82 inventoryManagement
83 inventoryPolicy
84 inventoryQuantity
85 inventoryQuantityAdjustment
86 oldInventoryQuantity
87 option1
88 option2
89 option3
90 position
91 presentmentPrices
92 price
93 requiresShipping
94 shopifyCreatedAt
95 shopifyUpdatedAt
96 sku
97 taxCode
98 taxable
99 title
100 updatedAt
101 weight
102 weightUnit
103 }
104 quiz {
105 id
106 state
107 body
108 createdAt
109 title
110 updatedAt
111 }
112 updatedAt
113 }
114 }
115 }
116 title
117 updatedAt
118 }
119 }
120 }
121}
Variables
json
{
"first": 1
}

Retrieving many Quiz records

Pages of Quiz 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 quizzes 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 Quizzes

Fetch a page of records with the quiz.findMany JS method or the quizzes GraphQL field. No options are required. The records returned will be implicitly sorted by ID ascending.

Find many Quizzes
const quizRecords = await api.quiz.findMany();
console.log(quizRecords.length); //=> a number
console.log(quizRecords[0].id); //=> a string
const [result, refresh] = useFindMany(api.quiz);
const { data, error, fetching } = result;
console.log(data?.length); //=> a number
console.log(data?.[0].length); //=> a string
1query FindManyQuizzes {
2 quizzes {
3 edges {
4 node {
5 __typename
6 id
7 state
8 # ...
9 createdAt
10 updatedAt
11 }
12 }
13 }
14}
Variables
json
{}

Retrieving a single Quiz 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 Quiz record by ID

Individual Quiz 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 Quizzes
const quizRecord = await api.quiz.findById("some-value");
console.log(quizRecord.id); //=> a string
const [result, refresh] = useFindBy(api.quiz.findById, "some-value");
const { data, error, fetching } = result;
console.log(data?.id); //=> a string

Retrieving a single Quiz record by Title

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

Find Quizzes
const quizRecord = await api.quiz.findByTitle("some-value");
console.log(quizRecord.id); //=> a string
const [result, refresh] = useFindBy(api.quiz.findByTitle, "some-value");
const { data, error, fetching } = result;
console.log(data?.id); //=> a string

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 QuizSort 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 QuizSort instead of just one.

GraphQL
1input QuizSort {
2 id: SortOrder
3 createdAt: SortOrder
4 updatedAt: SortOrder
5 state: SortOrder
6 title: SortOrder
7 body: SortOrder
8}

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

Sort Quiz by most recently created
const quizRecords = await api.quiz.findMany({ sort: { createdAt: "Descending" } });
const [result, refresh] = useFindMany(api.quiz, {
sort: { createdAt: "Descending" },
});
const { data, error, fetching } = result;
1query FindManyQuizzes($sort: [QuizSort!]) {
2 quizzes(sort: $sort) {
3 edges {
4 node {
5 __typename
6 id
7 state
8 # ...
9 createdAt
10 updatedAt
11 }
12 }
13 }
14}
Variables
json
{
"sort": {
"createdAt": "Descending"
}
}

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

Sort Quiz by multiple fields
const quizRecords = await api.quiz.findMany({
sort: [{ state: "Descending" }, { createdAt: "Ascending" }],
});
const [result, refresh] = useFindMany(api.quiz, {
sort: [{ state: "Descending" }, { createdAt: "Ascending" }],
});
const { data, error, fetching } = result;
1query FindManyQuizzes($sort: [QuizSort!]) {
2 quizzes(sort: $sort) {
3 edges {
4 node {
5 __typename
6 id
7 state
8 # ...
9 createdAt
10 updatedAt
11 }
12 }
13 }
14}
Variables
json
1{
2 "sort": [
3 {
4 "state": "Descending"
5 },
6 {
7 "createdAt": "Ascending"
8 }
9 ]
10}

All primitive field types in Gadget are sortable so you are able to sort by fields you have added to a model as well.

Sort Quizzes by ID descending
const quizRecords = await api.quiz.findMany({
sort: { id: "Descending" },
});
const [result, refresh] = useFindMany(api.quiz, {
sort: { id: "Descending" },
});
const { data, error, fetching } = result;
1query FindManyQuizzes($sort: [QuizSort!]) {
2 quizzes(sort: $sort) {
3 edges {
4 node {
5 __typename
6 id
7 state
8 # ...
9 createdAt
10 updatedAt
11 }
12 }
13 }
14}
Variables
json
{
"sort": {
"id": "Descending"
}
}

Searching

Quiz 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 Quizzes 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 Quizzes
const quizRecords = await api.quiz.findMany({
search: "a specific phrase to search for",
});
const [result, refresh] = useFindMany(api.quiz, {
search: "a specific phrase to search for",
});
const { data, error, fetching } = result;
1query FindManyQuizzes($search: String) {
2 quizzes(search: $search) {
3 edges {
4 node {
5 __typename
6 id
7 state
8 # ...
9 createdAt
10 updatedAt
11 }
12 }
13 }
14}
Variables
json
{
"search": "a specific phrase to search for"
}

Filtering

Quiz 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 Quizzes 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.

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

Records can be filtered by multiple different fields. 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.

Available filters
GraphQL
1input QuizFilter {
2 AND: [QuizFilter]
3 OR: [QuizFilter]
4 NOT: [QuizFilter]
5 id: IDFilter
6 createdAt: DateTimeFilter
7 updatedAt: DateTimeFilter
8 state: StateFilter
9 title: StringFilter
10 body: StringFilter
11}
Find Quizzes created in the last day
const yesterday = new Date(Date.now() - 864e5);
const quizRecords = await api.quiz.findMany({
filter: { createdAt: { greaterThan: yesterday } },
});
const yesterday = new Date(Date.now() - 864e5);
const [result, refresh] = useFindMany(api.quiz, {
filter: { createdAt: { greaterThan: yesterday } },
});
const { data, error, fetching } = result;
1query FindManyQuizzes($filter: [QuizFilter!]) {
2 quizzes(filter: $filter) {
3 edges {
4 node {
5 __typename
6 id
7 state
8 # ...
9 createdAt
10 updatedAt
11 }
12 }
13 }
14}
Variables
json
1{
2 "filter": {
3 "createdAt": {
4 "greaterThan": "2022-10-03T06:19:34.785Z"
5 }
6 }
7}
Quizzes created this week or updated today
1const yesterday = new Date(Date.now() - 86400000);
2const oneWeekAgo = new Date(Date.now() - 604800000);
3const quizRecords = await api.quiz.findMany({
4 filter: {
5 OR: [
6 {
7 createdAt: { greaterThan: oneWeekAgo },
8 },
9 {
10 updated: { 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.quiz, {
4 filter: {
5 OR: [
6 {
7 createdAt: { greaterThan: oneWeekAgo },
8 },
9 {
10 updated: { greaterThan: yesterday },
11 },
12 ],
13 },
14});
15const { data, error, fetching } = result;
1query FindManyQuizzes($filter: [QuizFilter!]) {
2 quizzes(filter: $filter) {
3 edges {
4 node {
5 __typename
6 id
7 state
8 # ...
9 createdAt
10 updatedAt
11 }
12 }
13 }
14}
Variables
json
1{
2 "filter": {
3 "OR": [
4 {
5 "createdAt": {
6 "greaterThan": "2022-09-27T06:19:34.785Z"
7 }
8 },
9 {
10 "updated": {
11 "greaterThan": "2022-10-03T06:19:34.785Z"
12 }
13 }
14 ]
15 }
16}
Filter records that are in the created state
const quizRecords = await api.quiz.findMany({
filter: {
state: { inState: "created" },
},
});
1const [result, refresh] = useFindMany(api.quiz, {
2 filter: {
3 state: { inState: "created" },
4 },
5});
6const { data, error, fetching } = result;
1query FindManyQuizzes($filter: [QuizFilter!]) {
2 quizzes(filter: $filter) {
3 edges {
4 node {
5 __typename
6 id
7 state
8 # ...
9 createdAt
10 updatedAt
11 }
12 }
13 }
14}
Variables
json
1{
2 "filter": {
3 "state": {
4 "inState": "created"
5 }
6 }
7}

Most field types in Gadget are filterable, so you are able to filter by fields you have added to a model as well.

const quizRecords = await api.quiz.findMany({
filter: {
id: { isSet: true },
},
});
1const [result, refresh] = useFindMany(api.quiz, {
2 filter: {
3 id: { isSet: true },
4 },
5});
6const { data, error, fetching } = result;
1query FindManyQuizzes($filter: [QuizFilter!]) {
2 quizzes(filter: $filter) {
3 edges {
4 node {
5 __typename
6 id
7 state
8 # ...
9 createdAt
10 updatedAt
11 }
12 }
13 }
14}
Variables
json
1{
2 "filter": {
3 "id": {
4 "isSet": true
5 }
6 }
7}

Pagination

All Gadget record lists, including the top level Quiz finder as well as associations to Quiz, are structured as GraphQL connections. GraphQL connections are the defacto 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 Quiz 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.

Quiz 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 Quizzes
const quizRecords = await api.quiz.findMany({ first: 25 });
console.log(quizRecords.length); //=> no greater than 25
const [result, refresh] = useFindMany(api.quiz, { first: 25 });
const { data, error, fetching } = result;
console.log(data?.length); //=> no greater than 25
1query FindManyQuizzes($first: Int, $after: String) {
2 quizzes(first: $first, after: $after) {
3 edges {
4 cursor
5 node {
6 __typename
7 id
8 state
9 # ...
10 createdAt
11 updatedAt
12 }
13 }
14 pageInfo {
15 endCursor
16 hasNextPage
17 hasPreviousPage
18 startCursor
19 }
20 }
21}
Variables
json
{
"first": 25
}

The after cursor used in this example data won't return any records if used in a real API request.

Next 25 Quiz records after cursor
const quizRecords = await api.quiz.findMany({ after: "abcdefg", first: 25 });
const [result, refresh] = useFindMany(api.quiz, { after: "abcdefg", first: 25 });
const { data, error, fetching } = result;
1query FindManyQuizzes($first: Int, $after: String) {
2 quizzes(first: $first, after: $after) {
3 edges {
4 cursor
5 node {
6 __typename
7 id
8 state
9 # ...
10 createdAt
11 updatedAt
12 }
13 }
14 pageInfo {
15 endCursor
16 hasNextPage
17 hasPreviousPage
18 startCursor
19 }
20 }
21}
Variables
json
{
"first": 25,
"after": "abcdefg"
}

Pagination Limits

Root level record finders like quizzes 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 HasMany or HasManyThrough 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, the record lists returned from find many 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 quizRecords =
2 await api.quiz.findMany();
3if (quizRecords.hasNextPage) {
4 const nextPage =
5 await quizRecords.nextPage();
6}
7if (quizRecords.hasPreviousPage) {
8 const prevPage =
9 await quizRecords.previousPage();
10}

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 Quiz 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 Quiz, as well as concise representations of each of the relationships containing an id and an automatically inferred title field. If you don't pass a select option to a record finder, this default selection will be used.

Select only some Quiz fields
// fetch only the id, state, and createdAt field
const quizRecords = await api.quiz.findMany({
select: { id: true, state: true, createdAt: true },
});
// fetch only the id, state, and createdAt field
const [result, refresh] = useFindMany(api.quiz, {
select: { id: true, state: true, createdAt: true },
});
const { data, error, fetching } = result;
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. For more information, see Type Safety .

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 Quiz fields
1// fetch the id, state, and createdAt field, and fetch some nested fields from an example relationship field named `someRelatedObject`
2const quizRecords = await api.quiz.findMany({
3 select: {
4 id: true,
5 state: true,
6 createdAt: true,
7 someRelatedObject: { id: true, createdAt: true },
8 },
9});
1// fetch the id, state, and createdAt field, and fetch some nested fields from an example relationship field named `someRelatedObject`
2const [result, refresh] = useFindMany(api.quiz, {
3 select: {
4 id: true,
5 state: true,
6 createdAt: true,
7 someRelatedObject: { id: true, createdAt: true },
8 },
9});
10const { data, error, fetching } = result;

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 quizRecords = await api.quiz.findMany({
2 search: "<some search query>",
3 sort: { createdAt: "Descending" },
4 filter: { updatedAt: { greaterThan: new Date(Date.now() - 864e5) } },
5 select: { id: true, createdAt: true },
6 first: 25,
7 after: "abcdefg",
8});
1const [result, refresh] = useFindMany(api.quiz, {
2 search: "<some search query>",
3 sort: { createdAt: "Descending" },
4 filter: { updatedAt: { greaterThan: new Date(Date.now() - 864e5) } },
5 select: { id: true, createdAt: true },
6 first: 25,
7 after: "abcdefg",
8});
9const { data, error, fetching } = result;
1query FindManyQuizzes(
2 $after: String
3 $before: String
4 $first: Int
5 $last: Int
6 $search: String
7 $sort: [QuizSort!]
8 $filter: [QuizFilter!]
9) {
10 quizzes(
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 cursor
21 node {
22 __typename
23 id
24 state
25 body
26 createdAt
27 questions {
28 edges {
29 node {
30 id
31 state
32 body
33 createdAt
34 imageUrl
35 quiz {
36 id
37 state
38 body
39 createdAt
40 title
41 updatedAt
42 }
43 required
44 sequence
45 title
46 updatedAt
47 }
48 }
49 }
50 responses {
51 edges {
52 node {
53 id
54 state
55 conversionState
56 createdAt
57 email
58 quiz {
59 id
60 state
61 body
62 createdAt
63 title
64 updatedAt
65 }
66 result {
67 id
68 state
69 body
70 createdAt
71 imageUrl
72 updatedAt
73 }
74 updatedAt
75 }
76 }
77 }
78 results {
79 edges {
80 node {
81 id
82 state
83 body
84 createdAt
85 imageUrl
86 productSuggestion {
87 id
88 state
89 barcode
90 compareAtPrice
91 createdAt
92 fulfillmentService
93 grams
94 inventoryManagement
95 inventoryPolicy
96 inventoryQuantity
97 inventoryQuantityAdjustment
98 oldInventoryQuantity
99 option1
100 option2
101 option3
102 position
103 presentmentPrices
104 price
105 requiresShipping
106 shopifyCreatedAt
107 shopifyUpdatedAt
108 sku
109 taxCode
110 taxable
111 title
112 updatedAt
113 weight
114 weightUnit
115 }
116 quiz {
117 id
118 state
119 body
120 createdAt
121 title
122 updatedAt
123 }
124 updatedAt
125 }
126 }
127 }
128 title
129 updatedAt
130 }
131 }
132 pageInfo {
133 endCursor
134 hasNextPage
135 hasPreviousPage
136 startCursor
137 }
138 }
139}
Variables
json
1{
2 "search": "<some search query>",
3 "sort": {
4 "createdAt": "Descending"
5 },
6 "filter": {
7 "updatedAt": {
8 "greaterThan": "2022-10-03T06:19:34.923Z"
9 }
10 },
11 "first": 25,
12 "after": "abcdefg"
13}

Invoking Actions

Quiz records are changed by invoking Actions. Actions are the things that "do" stuff -- update records, make API calls, call backend code, etc. Actions 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 "@gadget-client/example-app";
5
6// must be in an async function to use `await` syntax
7const runAction = async () => {
8 try {
9 return await api.exampleModel.create(
10 {
11 exampleModel: {
12 name: "example record name",
13 },
14 }
15 );
16 } catch (error) {
17 if (
18 error instanceof
19 GadgetOperationError
20 ) {
21 // a recognized general error has occurred, retry the operation or inspect error.code`
22 console.error(error);
23 } else if (
24 error instanceof
25 InvalidRecordError
26 ) {
27 // the submitted input data for the action was invalid, inspect the invalid fields which `InvalidRecordError` exposes
28 console.error(
29 error.validationErrors
30 );
31 } else {
32 // 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 ti
33 throw error;
34 }
35 }
36};

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

Quiz Create

The Create action transitions a Quiz from Start to Created.

Input

Create accepts the following input parameters:

Create Input Data
1export interface CreateQuizInput {
2 title?: (Scalars["String"] | null) | null;
3
4 body?: (Scalars["String"] | null) | null;
5
6 responses?: (ResponseHasManyInput | null)[];
7
8 results?: (ResultHasManyInput | null)[];
9
10 questions?: (QuestionHasManyInput | null)[];
11}
12
13export interface CreateQuizArguments {
14 quiz?: CreateQuizInput | null;
15}
1input CreateQuizInput {
2 title: String
3 body: String
4 responses: [ResponseHasManyInput]
5 results: [ResultHasManyInput]
6 questions: [QuestionHasManyInput]
7}
8
9input CreateQuizArguments {
10 quiz: CreateQuizInput
11}
Example Create Invocation
1const quizRecord = await api.quiz.create({
2 quiz: {
3 // field values for Quiz
4 },
5});
6console.log(quizRecord.id); //=> a string
1const [result, createQuiz] = useAction(api.quiz.create);
2const { data, error, fetching } = result;
3await createQuiz({
4 quiz: {
5 // field values for Quiz
6 },
7});
8console.log(data?.id); //=> a string
1mutation ($quiz: CreateQuizInput) {
2 createQuiz(quiz: $quiz) {
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 quiz {
18 __typename
19 id
20 state
21 body
22 createdAt
23 questions {
24 edges {
25 node {
26 id
27 state
28 body
29 createdAt
30 imageUrl
31 quiz {
32 id
33 state
34 body
35 createdAt
36 title
37 updatedAt
38 }
39 required
40 sequence
41 title
42 updatedAt
43 }
44 }
45 }
46 responses {
47 edges {
48 node {
49 id
50 state
51 conversionState
52 createdAt
53 email
54 quiz {
55 id
56 state
57 body
58 createdAt
59 title
60 updatedAt
61 }
62 result {
63 id
64 state
65 body
66 createdAt
67 imageUrl
68 updatedAt
69 }
70 updatedAt
71 }
72 }
73 }
74 results {
75 edges {
76 node {
77 id
78 state
79 body
80 createdAt
81 imageUrl
82 productSuggestion {
83 id
84 state
85 barcode
86 compareAtPrice
87 createdAt
88 fulfillmentService
89 grams
90 inventoryManagement
91 inventoryPolicy
92 inventoryQuantity
93 inventoryQuantityAdjustment
94 oldInventoryQuantity
95 option1
96 option2
97 option3
98 position
99 presentmentPrices
100 price
101 requiresShipping
102 shopifyCreatedAt
103 shopifyUpdatedAt
104 sku
105 taxCode
106 taxable
107 title
108 updatedAt
109 weight
110 weightUnit
111 }
112 quiz {
113 id
114 state
115 body
116 createdAt
117 title
118 updatedAt
119 }
120 updatedAt
121 }
122 }
123 }
124 title
125 updatedAt
126 }
127 }
128}
Variables
json
{
"quiz": {}
}
Output

Create returns the Quiz. 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.

Create Output Data
type CreateQuizResult {
success: Boolean!
errors: [ExecutionError!]
quiz: Quiz
}

Quiz Delete

The Delete action destroys the record.

Input

Delete operates on one Quiz in particular, identified by the id variable.

Example Delete Invocation
await api.quiz.delete("some-id");
const [result, deleteQuiz] = useAction(api.quiz.delete);
const { data, error, fetching } = result;
await deleteQuiz({
id: "some-id",
});
1mutation ($id: GadgetID!) {
2 deleteQuiz(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": "some-id"
}
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
type DeleteQuizResult {
success: Boolean!
errors: [ExecutionError!]
}

Quiz Update

The Update action transitions a Quiz from Created to Created.

Input

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

Update Input Data
1export interface UpdateQuizInput {
2 title?: (Scalars["String"] | null) | null;
3
4 body?: (Scalars["String"] | null) | null;
5
6 responses?: (ResponseHasManyInput | null)[];
7
8 results?: (ResultHasManyInput | null)[];
9
10 questions?: (QuestionHasManyInput | null)[];
11}
12
13export interface UpdateQuizArguments {
14 quiz?: UpdateQuizInput | null;
15}
1input UpdateQuizInput {
2 title: String
3 body: String
4 responses: [ResponseHasManyInput]
5 results: [ResultHasManyInput]
6 questions: [QuestionHasManyInput]
7}
8
9input UpdateQuizArguments {
10 quiz: UpdateQuizInput
11}
Example Update Invocation
1const quizRecord = await api.quiz.update("some-id", {
2 quiz: {
3 // field values for Quiz
4 },
5});
6console.log(quizRecord.id); //=> a string
1const [result, updateQuiz] = useAction(api.quiz.update);
2const { data, error, fetching } = result;
3await updateQuiz({
4 id: "some-id",
5 quiz: {
6 // field values for Quiz
7 },
8});
9console.log(data?.id); //=> a string
1mutation ($id: GadgetID!, $quiz: UpdateQuizInput) {
2 updateQuiz(id: $id, quiz: $quiz) {
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 quiz {
18 __typename
19 id
20 state
21 body
22 createdAt
23 questions {
24 edges {
25 node {
26 id
27 state
28 body
29 createdAt
30 imageUrl
31 quiz {
32 id
33 state
34 body
35 createdAt
36 title
37 updatedAt
38 }
39 required
40 sequence
41 title
42 updatedAt
43 }
44 }
45 }
46 responses {
47 edges {
48 node {
49 id
50 state
51 conversionState
52 createdAt
53 email
54 quiz {
55 id
56 state
57 body
58 createdAt
59 title
60 updatedAt
61 }
62 result {
63 id
64 state
65 body
66 createdAt
67 imageUrl
68 updatedAt
69 }
70 updatedAt
71 }
72 }
73 }
74 results {
75 edges {
76 node {
77 id
78 state
79 body
80 createdAt
81 imageUrl
82 productSuggestion {
83 id
84 state
85 barcode
86 compareAtPrice
87 createdAt
88 fulfillmentService
89 grams
90 inventoryManagement
91 inventoryPolicy
92 inventoryQuantity
93 inventoryQuantityAdjustment
94 oldInventoryQuantity
95 option1
96 option2
97 option3
98 position
99 presentmentPrices
100 price
101 requiresShipping
102 shopifyCreatedAt
103 shopifyUpdatedAt
104 sku
105 taxCode
106 taxable
107 title
108 updatedAt
109 weight
110 weightUnit
111 }
112 quiz {
113 id
114 state
115 body
116 createdAt
117 title
118 updatedAt
119 }
120 updatedAt
121 }
122 }
123 }
124 title
125 updatedAt
126 }
127 }
128}
Variables
json
{
"id": "some-id",
"quiz": {}
}
Output

Update returns the Quiz. 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
type UpdateQuizResult {
success: Boolean!
errors: [ExecutionError!]
quiz: Quiz
}

Linking to an Existing Child Record

During a create or update operation, you can link to existing child records simply by nesting the data structure on your operation, using an update object wrapper around the child record's properties.

Existing nested child
1const quizRecord = await api.quiz.create({
2 quiz: {
3 title: "titleValue",
4 responses: {
5 // Updates existing `response` record
6 // (`id` of record required),
7 // and links it to quiz.
8 update: {
9 id: "123",
10 result: "responsesResultValue",
11 },
12 },
13 },
14});
15console.log(quizRecord.id); //=> a string
1const [result, createQuiz] = useAction(api.quiz.create);
2const { data, error, fetching } = result;
3await createQuiz({
4 quiz: {
5 title: "titleValue",
6 responses: {
7 // Updates existing `response` record
8 // (`id` of record required),
9 // and links it to quiz.
10 update: {
11 id: "123",
12 result: "responsesResultValue",
13 },
14 },
15 },
16});
17console.log(data?.id); //=> a string
1mutation ($quiz: CreateQuizInput) {
2 createQuiz(quiz: $quiz) {
3 success
4 errors {
5 message
6 }
7 quiz {
8 id
9 title
10 responses {
11 edges {
12 node {
13 id
14 }
15 }
16 }
17 }
18 }
19}
Variables
json
1{
2 "title": "titleValue",
3 "responses": {
4 "update": {
5 "id": "123",
6 "result": "responsesResultValue"
7 }
8 }
9}

Linking to a New Child Record

During a create or update operation, you can create linked child records simply by nesting the data structure on your operation, using a create object wrapper around the child record's properties.

New nested child
1const quizRecord = await api.quiz.create({
2 quiz: {
3 title: "titleValue",
4 responses: {
5 // Creates `response` record,
6 // linked to quiz.
7 create: {
8 result: "responsesResultValue",
9 },
10 },
11 },
12});
13console.log(quizRecord.id); //=> a string
1const [result, createQuiz] = useAction(api.quiz.create);
2const { data, error, fetching } = result;
3await createQuiz({
4 quiz: {
5 title: "titleValue",
6 responses: {
7 // Creates `response` record,
8 // linked to quiz.
9 create: {
10 result: "responsesResultValue",
11 },
12 },
13 },
14});
15console.log(data?.id); //=> a string
1mutation ($quiz: CreateQuizInput) {
2 createQuiz(quiz: $quiz) {
3 success
4 errors {
5 message
6 }
7 quiz {
8 id
9 title
10 responses {
11 edges {
12 node {
13 id
14 }
15 }
16 }
17 }
18 }
19}
Variables
json
1{
2 "title": "titleValue",
3 "responses": {
4 "create": {
5 "result": "responsesResultValue"
6 }
7 }
8}

Linking to an Existing Parent Record

When you wish to link to an existing parent record, you must use a _link property in your data, with the id of the parent record that this child record will belong to.

Linked creation
1const responseRecord = await api.response.create({
2 response: {
3 result: "resultValue",
4 // Links response to existing
5 // parent `quiz` record.
6 quiz: {
7 _link: "123",
8 },
9 },
10});
11console.log(responseRecord.id); //=> a string
1const [result, createResponse] = useAction(api.response.create);
2const { data, error, fetching } = result;
3await createResponse({
4 response: {
5 result: "resultValue",
6 // Links response to existing
7 // parent `quiz` record.
8 quiz: {
9 _link: "123",
10 },
11 },
12});
13console.log(data?.id); //=> a string
1mutation ($response: CreateResponseInput) {
2 createResponse(response: $response) {
3 success
4 errors {
5 message
6 }
7 response {
8 id
9 result
10 quiz {
11 id
12 }
13 }
14 }
15}
Variables
json
1{
2 "result": "resultValue",
3 "quiz": {
4 "_link": "123"
5 }
6}

Linking to a New Parent Record

You cannot directly link to a new parent record when creation a child record. However, you can jointly create both parent and child via the Linking to a New Child Record method.

Bulk Actions

Actions that support it can be performed in bulk. Bulk Actions are executed as a single GraphQL mutation and have a corresponding function available in the API client libraries. Bulk Actions are performed on a set of ids. Bulk Actions repeat the same action, with the same options and parameters, across all ids and should not be confused with batching up different actions in the same request.

Bulk Actions will be performed on the entire set. If an action fails on an individual record, the Bulk Action will still occur on the other records in the set. Only the records which completed the action successfully will be returned.

Bulk Quiz Delete

The Bulk Delete action destroys the records.

Input

Bulk Delete operates on a set of Quizzes, identified by the ids variable.

Example Delete Invocation
await api.quiz.bulkDelete(["some-id", "another-id"]);
const [quizResult, bulkDelete] = useBulkAction(api.quiz.bulkDelete);
const { data, error, fetching } = result;
await bulkDelete({ ids: ["some-id", "another-id"] });
1mutation ($ids: [GadgetID!]!) {
2 bulkDeleteQuizzes(ids: $ids) {
3 success
4 errors {
5 message
6 }
7 }
8}
Variables
json
1{
2 "ids": [
3 "some-id",
4 "another-id"
5 ]
6}
Output

Bulk 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
type BulkDeleteQuizzesResult {
success: Boolean!
errors: [ExecutionError!]
}