Result

This page documents the Result model.

Data Shape

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

Result Schema
1export interface Result {
2 __typename: "Result";
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 answers: AnswerConnection;
17
18 body: Scalars["String"];
19
20 quiz: Quiz | null;
21
22 quizId: Scalars["GadgetID"] | null;
23
24 imageUrl: Scalars["URL"] | null;
25
26 responses: ResponseConnection;
27
28 productSuggestion: ShopifyProductVariant | null;
29
30 productSuggestionId: Scalars["GadgetID"] | null;
31
32 /** Get all the fields for this record. Useful for not having to list out all the fields you want to retrieve, but slower. */
33 _all: Scalars["JSONObject"];
34}
1type Result {
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 answers(
22 """
23 Returns the items in the list that come after the specified cursor.
24 """
25 after: String
26
27 """
28 Returns the first n items from the list.
29 """
30 first: Int
31
32 """
33 Returns the items in the list that come before the specified cursor.
34 """
35 before: String
36
37 """
38 Returns the last n items from the list.
39 """
40 last: Int
41
42 """
43 A list of sort orders to return the results in
44 """
45 sort: [AnswerSort!]
46
47 """
48 A list of filters to refine the results by
49 """
50 filter: [AnswerFilter!]
51
52 """
53 A free form text search query to find records matching
54 """
55 search: String
56 ): AnswerConnection!
57 body: String!
58 quiz: Quiz
59 quizId: GadgetID
60 imageUrl: URL
61 responses(
62 """
63 Returns the items in the list that come after the specified cursor.
64 """
65 after: String
66
67 """
68 Returns the first n items from the list.
69 """
70 first: Int
71
72 """
73 Returns the items in the list that come before the specified cursor.
74 """
75 before: String
76
77 """
78 Returns the last n items from the list.
79 """
80 last: Int
81
82 """
83 A list of sort orders to return the results in
84 """
85 sort: [ResponseSort!]
86
87 """
88 A list of filters to refine the results by
89 """
90 filter: [ResponseFilter!]
91
92 """
93 A free form text search query to find records matching
94 """
95 search: String
96 ): ResponseConnection!
97 productSuggestion: ShopifyProductVariant
98 productSuggestionId: GadgetID
99
100 """
101 Get all the fields for this record. Useful for not having to list out all the fields you want to retrieve, but slower.
102 """
103 _all: JSONObject!
104}

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

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

Individual Result 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 Result
const resultRecord = await api.result.findOne("some-id");
console.log(resultRecord.id); //=> a string
console.log(resultRecord.createdAt); //=> a Date object
const [result, refresh] = useFindOne(api.result, "some-id");
const { data, error, fetching } = result;
console.log(data?.id); //=> a string
console.log(data?.createdAt); //=> a Date object
1query GetOneResult($id: GadgetID!) {
2 result(id: $id) {
3 __typename
4 id
5 state
6 answers {
7 edges {
8 node {
9 id
10 state
11 createdAt
12 question {
13 id
14 state
15 body
16 createdAt
17 imageUrl
18 required
19 sequence
20 title
21 updatedAt
22 }
23 response {
24 id
25 state
26 conversionState
27 createdAt
28 email
29 updatedAt
30 }
31 result {
32 id
33 state
34 body
35 createdAt
36 imageUrl
37 updatedAt
38 }
39 sequence
40 text
41 updatedAt
42 }
43 }
44 }
45 body
46 createdAt
47 imageUrl
48 productSuggestion {
49 id
50 state
51 barcode
52 compareAtPrice
53 createdAt
54 fulfillmentService
55 grams
56 inventoryManagement
57 inventoryPolicy
58 inventoryQuantity
59 inventoryQuantityAdjustment
60 oldInventoryQuantity
61 option1
62 option2
63 option3
64 position
65 presentmentPrices
66 price
67 product {
68 id
69 state
70 body
71 createdAt
72 handle
73 productType
74 publishedAt
75 publishedScope
76 shopifyCreatedAt
77 shopifyUpdatedAt
78 tags
79 templateSuffix
80 title
81 updatedAt
82 vendor
83 }
84 productImage {
85 id
86 state
87 createdAt
88 height
89 position
90 shopifyCreatedAt
91 shopifyUpdatedAt
92 source
93 updatedAt
94 width
95 }
96 requiresShipping
97 shop {
98 id
99 state
100 accessToken
101 address1
102 address2
103 checkoutApiSupported
104 city
105 cookieConsentLevel
106 country
107 countryCode
108 countryName
109 countyTaxes
110 createdAt
111 currency
112 customerEmail
113 domain
114 eligibleForCardReaderGiveaway
115 eligibleForPayments
116 email
117 enabledPresentmentCurrencies
118 finances
119 forceSsl
120 googleAppsDomain
121 googleAppsLoginEnabled
122 grantedScopes
123 hasDiscounts
124 hasGiftCards
125 hasStorefront
126 ianaTimezone
127 installedViaApiKey
128 latitude
129 longitude
130 moneyFormat
131 moneyInEmailsFormat
132 moneyWithCurrencyFormat
133 moneyWithCurrencyInEmailsFormat
134 multiLocationEnabled
135 myshopifyDomain
136 name
137 passwordEnabled
138 phone
139 planDisplayName
140 planName
141 preLaunchEnabled
142 primaryLocale
143 province
144 provinceCode
145 registeredWebhooks
146 requiresExtraPaymentsAgreement
147 setupRequired
148 shopOwner
149 shopifyCreatedAt
150 shopifyUpdatedAt
151 source
152 taxShipping
153 taxesIncluded
154 timezone
155 updatedAt
156 weightUnit
157 zipCode
158 }
159 shopifyCreatedAt
160 shopifyUpdatedAt
161 sku
162 taxCode
163 taxable
164 title
165 updatedAt
166 weight
167 weightUnit
168 }
169 quiz {
170 id
171 state
172 body
173 createdAt
174 title
175 updatedAt
176 }
177 responses {
178 edges {
179 node {
180 id
181 state
182 conversionState
183 createdAt
184 email
185 quiz {
186 id
187 state
188 body
189 createdAt
190 title
191 updatedAt
192 }
193 result {
194 id
195 state
196 body
197 createdAt
198 imageUrl
199 updatedAt
200 }
201 updatedAt
202 }
203 }
204 }
205 updatedAt
206 }
207}
Variables
json
{
"id": "some-id"
}

Retrieving the first of many Result 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 Result
const resultRecord = await api.result.findFirst();
console.log(resultRecord.id); //=> a string
console.log(resultRecord.createdAt); //=> a Date object
const [result, refresh] = useFindFirst(api.result);
const { data, error, fetching } = result;
console.log(data?.id); //=> a string
console.log(data?.createdAt); //=> a Date object
1query FindManyResults(
2 $first: Int
3 $search: String
4 $sort: [ResultSort!]
5 $filter: [ResultFilter!]
6) {
7 results(first: $first, search: $search, sort: $sort, filter: $filter) {
8 edges {
9 node {
10 __typename
11 id
12 state
13 answers {
14 edges {
15 node {
16 id
17 state
18 createdAt
19 question {
20 id
21 state
22 body
23 createdAt
24 imageUrl
25 required
26 sequence
27 title
28 updatedAt
29 }
30 response {
31 id
32 state
33 conversionState
34 createdAt
35 email
36 updatedAt
37 }
38 result {
39 id
40 state
41 body
42 createdAt
43 imageUrl
44 updatedAt
45 }
46 sequence
47 text
48 updatedAt
49 }
50 }
51 }
52 body
53 createdAt
54 imageUrl
55 productSuggestion {
56 id
57 state
58 barcode
59 compareAtPrice
60 createdAt
61 fulfillmentService
62 grams
63 inventoryManagement
64 inventoryPolicy
65 inventoryQuantity
66 inventoryQuantityAdjustment
67 oldInventoryQuantity
68 option1
69 option2
70 option3
71 position
72 presentmentPrices
73 price
74 product {
75 id
76 state
77 body
78 createdAt
79 handle
80 productType
81 publishedAt
82 publishedScope
83 shopifyCreatedAt
84 shopifyUpdatedAt
85 tags
86 templateSuffix
87 title
88 updatedAt
89 vendor
90 }
91 productImage {
92 id
93 state
94 createdAt
95 height
96 position
97 shopifyCreatedAt
98 shopifyUpdatedAt
99 source
100 updatedAt
101 width
102 }
103 requiresShipping
104 shop {
105 id
106 state
107 accessToken
108 address1
109 address2
110 checkoutApiSupported
111 city
112 cookieConsentLevel
113 country
114 countryCode
115 countryName
116 countyTaxes
117 createdAt
118 currency
119 customerEmail
120 domain
121 eligibleForCardReaderGiveaway
122 eligibleForPayments
123 email
124 enabledPresentmentCurrencies
125 finances
126 forceSsl
127 googleAppsDomain
128 googleAppsLoginEnabled
129 grantedScopes
130 hasDiscounts
131 hasGiftCards
132 hasStorefront
133 ianaTimezone
134 installedViaApiKey
135 latitude
136 longitude
137 moneyFormat
138 moneyInEmailsFormat
139 moneyWithCurrencyFormat
140 moneyWithCurrencyInEmailsFormat
141 multiLocationEnabled
142 myshopifyDomain
143 name
144 passwordEnabled
145 phone
146 planDisplayName
147 planName
148 preLaunchEnabled
149 primaryLocale
150 province
151 provinceCode
152 registeredWebhooks
153 requiresExtraPaymentsAgreement
154 setupRequired
155 shopOwner
156 shopifyCreatedAt
157 shopifyUpdatedAt
158 source
159 taxShipping
160 taxesIncluded
161 timezone
162 updatedAt
163 weightUnit
164 zipCode
165 }
166 shopifyCreatedAt
167 shopifyUpdatedAt
168 sku
169 taxCode
170 taxable
171 title
172 updatedAt
173 weight
174 weightUnit
175 }
176 quiz {
177 id
178 state
179 body
180 createdAt
181 title
182 updatedAt
183 }
184 responses {
185 edges {
186 node {
187 id
188 state
189 conversionState
190 createdAt
191 email
192 quiz {
193 id
194 state
195 body
196 createdAt
197 title
198 updatedAt
199 }
200 result {
201 id
202 state
203 body
204 createdAt
205 imageUrl
206 updatedAt
207 }
208 updatedAt
209 }
210 }
211 }
212 updatedAt
213 }
214 }
215 }
216}
Variables
json
{
"first": 1
}

Retrieving many Result records

Pages of Result 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 results 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 Results

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

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

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

Individual Result 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 Results
const resultRecord = await api.result.findById("some-value");
console.log(resultRecord.id); //=> a string
const [result, refresh] = useFindBy(api.result.findById, "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 ResultSort 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 ResultSort instead of just one.

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

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

Sort Result by most recently created
const resultRecords = await api.result.findMany({
sort: { createdAt: "Descending" },
});
const [result, refresh] = useFindMany(api.result, {
sort: { createdAt: "Descending" },
});
const { data, error, fetching } = result;
1query FindManyResults($sort: [ResultSort!]) {
2 results(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 Result by multiple fields
const resultRecords = await api.result.findMany({
sort: [{ state: "Descending" }, { createdAt: "Ascending" }],
});
const [result, refresh] = useFindMany(api.result, {
sort: [{ state: "Descending" }, { createdAt: "Ascending" }],
});
const { data, error, fetching } = result;
1query FindManyResults($sort: [ResultSort!]) {
2 results(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 Results by ID descending
const resultRecords = await api.result.findMany({
sort: { id: "Descending" },
});
const [result, refresh] = useFindMany(api.result, {
sort: { id: "Descending" },
});
const { data, error, fetching } = result;
1query FindManyResults($sort: [ResultSort!]) {
2 results(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

Result 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 Results 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 Results
const resultRecords = await api.result.findMany({
search: "a specific phrase to search for",
});
const [result, refresh] = useFindMany(api.result, {
search: "a specific phrase to search for",
});
const { data, error, fetching } = result;
1query FindManyResults($search: String) {
2 results(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

Result 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 Results 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 ResultFilter 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 ResultFilter {
2 AND: [ResultFilter]
3 OR: [ResultFilter]
4 NOT: [ResultFilter]
5 id: IDFilter
6 createdAt: DateTimeFilter
7 updatedAt: DateTimeFilter
8 state: StateFilter
9 body: StringFilter
10 quiz: IDFilter
11 imageUrl: StringFilter
12 productSuggestion: IDFilter
13}
Find Results created in the last day
const yesterday = new Date(Date.now() - 864e5);
const resultRecords = await api.result.findMany({
filter: { createdAt: { greaterThan: yesterday } },
});
const yesterday = new Date(Date.now() - 864e5);
const [result, refresh] = useFindMany(api.result, {
filter: { createdAt: { greaterThan: yesterday } },
});
const { data, error, fetching } = result;
1query FindManyResults($filter: [ResultFilter!]) {
2 results(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:42:02.325Z"
5 }
6 }
7}
Results created this week or updated today
1const yesterday = new Date(Date.now() - 86400000);
2const oneWeekAgo = new Date(Date.now() - 604800000);
3const resultRecords = await api.result.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.result, {
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 FindManyResults($filter: [ResultFilter!]) {
2 results(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:42:02.325Z"
7 }
8 },
9 {
10 "updated": {
11 "greaterThan": "2022-10-03T06:42:02.325Z"
12 }
13 }
14 ]
15 }
16}
Filter records that are in the created state
const resultRecords = await api.result.findMany({
filter: {
state: { inState: "created" },
},
});
1const [result, refresh] = useFindMany(api.result, {
2 filter: {
3 state: { inState: "created" },
4 },
5});
6const { data, error, fetching } = result;
1query FindManyResults($filter: [ResultFilter!]) {
2 results(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 resultRecords = await api.result.findMany({
filter: {
id: { isSet: true },
},
});
1const [result, refresh] = useFindMany(api.result, {
2 filter: {
3 id: { isSet: true },
4 },
5});
6const { data, error, fetching } = result;
1query FindManyResults($filter: [ResultFilter!]) {
2 results(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 Result finder as well as associations to Result, 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 Result 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.

Result 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 Results
const resultRecords = await api.result.findMany({ first: 25 });
console.log(resultRecords.length); //=> no greater than 25
const [result, refresh] = useFindMany(api.result, { first: 25 });
const { data, error, fetching } = result;
console.log(data?.length); //=> no greater than 25
1query FindManyResults($first: Int, $after: String) {
2 results(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 Result records after cursor
const resultRecords = await api.result.findMany({ after: "abcdefg", first: 25 });
const [result, refresh] = useFindMany(api.result, { after: "abcdefg", first: 25 });
const { data, error, fetching } = result;
1query FindManyResults($first: Int, $after: String) {
2 results(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 results 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 resultRecords =
2 await api.result.findMany();
3if (resultRecords.hasNextPage) {
4 const nextPage =
5 await resultRecords.nextPage();
6}
7if (resultRecords.hasPreviousPage) {
8 const prevPage =
9 await resultRecords.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 Result 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 Result, 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 Result fields
// fetch only the id, state, and createdAt field
const resultRecords = await api.result.findMany({
select: { id: true, state: true, createdAt: true },
});
// fetch only the id, state, and createdAt field
const [result, refresh] = useFindMany(api.result, {
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 Result fields
1// fetch the id, state, and createdAt field, and fetch some nested fields from an example relationship field named `someRelatedObject`
2const resultRecords = await api.result.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.result, {
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 resultRecords = await api.result.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.result, {
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 FindManyResults(
2 $after: String
3 $before: String
4 $first: Int
5 $last: Int
6 $search: String
7 $sort: [ResultSort!]
8 $filter: [ResultFilter!]
9) {
10 results(
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 answers {
26 edges {
27 node {
28 id
29 state
30 createdAt
31 question {
32 id
33 state
34 body
35 createdAt
36 imageUrl
37 required
38 sequence
39 title
40 updatedAt
41 }
42 response {
43 id
44 state
45 conversionState
46 createdAt
47 email
48 updatedAt
49 }
50 result {
51 id
52 state
53 body
54 createdAt
55 imageUrl
56 updatedAt
57 }
58 sequence
59 text
60 updatedAt
61 }
62 }
63 }
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 product {
87 id
88 state
89 body
90 createdAt
91 handle
92 productType
93 publishedAt
94 publishedScope
95 shopifyCreatedAt
96 shopifyUpdatedAt
97 tags
98 templateSuffix
99 title
100 updatedAt
101 vendor
102 }
103 productImage {
104 id
105 state
106 createdAt
107 height
108 position
109 shopifyCreatedAt
110 shopifyUpdatedAt
111 source
112 updatedAt
113 width
114 }
115 requiresShipping
116 shop {
117 id
118 state
119 accessToken
120 address1
121 address2
122 checkoutApiSupported
123 city
124 cookieConsentLevel
125 country
126 countryCode
127 countryName
128 countyTaxes
129 createdAt
130 currency
131 customerEmail
132 domain
133 eligibleForCardReaderGiveaway
134 eligibleForPayments
135 email
136 enabledPresentmentCurrencies
137 finances
138 forceSsl
139 googleAppsDomain
140 googleAppsLoginEnabled
141 grantedScopes
142 hasDiscounts
143 hasGiftCards
144 hasStorefront
145 ianaTimezone
146 installedViaApiKey
147 latitude
148 longitude
149 moneyFormat
150 moneyInEmailsFormat
151 moneyWithCurrencyFormat
152 moneyWithCurrencyInEmailsFormat
153 multiLocationEnabled
154 myshopifyDomain
155 name
156 passwordEnabled
157 phone
158 planDisplayName
159 planName
160 preLaunchEnabled
161 primaryLocale
162 province
163 provinceCode
164 registeredWebhooks
165 requiresExtraPaymentsAgreement
166 setupRequired
167 shopOwner
168 shopifyCreatedAt
169 shopifyUpdatedAt
170 source
171 taxShipping
172 taxesIncluded
173 timezone
174 updatedAt
175 weightUnit
176 zipCode
177 }
178 shopifyCreatedAt
179 shopifyUpdatedAt
180 sku
181 taxCode
182 taxable
183 title
184 updatedAt
185 weight
186 weightUnit
187 }
188 quiz {
189 id
190 state
191 body
192 createdAt
193 title
194 updatedAt
195 }
196 responses {
197 edges {
198 node {
199 id
200 state
201 conversionState
202 createdAt
203 email
204 quiz {
205 id
206 state
207 body
208 createdAt
209 title
210 updatedAt
211 }
212 result {
213 id
214 state
215 body
216 createdAt
217 imageUrl
218 updatedAt
219 }
220 updatedAt
221 }
222 }
223 }
224 updatedAt
225 }
226 }
227 pageInfo {
228 endCursor
229 hasNextPage
230 hasPreviousPage
231 startCursor
232 }
233 }
234}
Variables
json
1{
2 "search": "<some search query>",
3 "sort": {
4 "createdAt": "Descending"
5 },
6 "filter": {
7 "updatedAt": {
8 "greaterThan": "2022-10-03T06:42:02.476Z"
9 }
10 },
11 "first": 25,
12 "after": "abcdefg"
13}

Invoking Actions

Result 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.

Result Update

The Update action transitions a Result from Created to Created.

Input

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

Update Input Data
1export interface UpdateResultInput {
2 answers?: (AnswerHasManyInput | null)[];
3
4 body?: (Scalars["String"] | null) | null;
5
6 quiz?: QuizBelongsToInput | null;
7
8 imageUrl?: (Scalars["String"] | null) | null;
9
10 responses?: (ResponseHasManyInput | null)[];
11
12 productSuggestion?: ShopifyProductVariantBelongsToInput | null;
13}
14
15export interface UpdateResultArguments {
16 result?: UpdateResultInput | null;
17}
1input UpdateResultInput {
2 answers: [AnswerHasManyInput]
3 body: String
4 quiz: QuizBelongsToInput
5 imageUrl: String
6 responses: [ResponseHasManyInput]
7 productSuggestion: ShopifyProductVariantBelongsToInput
8}
9
10input UpdateResultArguments {
11 result: UpdateResultInput
12}
Example Update Invocation
1const resultRecord = await api.result.update("some-id", {
2 result: {
3 // field values for Result
4 },
5});
6console.log(resultRecord.id); //=> a string
1const [result, updateResult] = useAction(api.result.update);
2const { data, error, fetching } = result;
3await updateResult({
4 id: "some-id",
5 result: {
6 // field values for Result
7 },
8});
9console.log(data?.id); //=> a string
1mutation ($id: GadgetID!, $result: UpdateResultInput) {
2 updateResult(id: $id, result: $result) {
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 result {
18 __typename
19 id
20 state
21 answers {
22 edges {
23 node {
24 id
25 state
26 createdAt
27 question {
28 id
29 state
30 body
31 createdAt
32 imageUrl
33 required
34 sequence
35 title
36 updatedAt
37 }
38 response {
39 id
40 state
41 conversionState
42 createdAt
43 email
44 updatedAt
45 }
46 result {
47 id
48 state
49 body
50 createdAt
51 imageUrl
52 updatedAt
53 }
54 sequence
55 text
56 updatedAt
57 }
58 }
59 }
60 body
61 createdAt
62 imageUrl
63 productSuggestion {
64 id
65 state
66 barcode
67 compareAtPrice
68 createdAt
69 fulfillmentService
70 grams
71 inventoryManagement
72 inventoryPolicy
73 inventoryQuantity
74 inventoryQuantityAdjustment
75 oldInventoryQuantity
76 option1
77 option2
78 option3
79 position
80 presentmentPrices
81 price
82 product {
83 id
84 state
85 body
86 createdAt
87 handle
88 productType
89 publishedAt
90 publishedScope
91 shopifyCreatedAt
92 shopifyUpdatedAt
93 tags
94 templateSuffix
95 title
96 updatedAt
97 vendor
98 }
99 productImage {
100 id
101 state
102 createdAt
103 height
104 position
105 shopifyCreatedAt
106 shopifyUpdatedAt
107 source
108 updatedAt
109 width
110 }
111 requiresShipping
112 shop {
113 id
114 state
115 accessToken
116 address1
117 address2
118 checkoutApiSupported
119 city
120 cookieConsentLevel
121 country
122 countryCode
123 countryName
124 countyTaxes
125 createdAt
126 currency
127 customerEmail
128 domain
129 eligibleForCardReaderGiveaway
130 eligibleForPayments
131 email
132 enabledPresentmentCurrencies
133 finances
134 forceSsl
135 googleAppsDomain
136 googleAppsLoginEnabled
137 grantedScopes
138 hasDiscounts
139 hasGiftCards
140 hasStorefront
141 ianaTimezone
142 installedViaApiKey
143 latitude
144 longitude
145 moneyFormat
146 moneyInEmailsFormat
147 moneyWithCurrencyFormat
148 moneyWithCurrencyInEmailsFormat
149 multiLocationEnabled
150 myshopifyDomain
151 name
152 passwordEnabled
153 phone
154 planDisplayName
155 planName
156 preLaunchEnabled
157 primaryLocale
158 province
159 provinceCode
160 registeredWebhooks
161 requiresExtraPaymentsAgreement
162 setupRequired
163 shopOwner
164 shopifyCreatedAt
165 shopifyUpdatedAt
166 source
167 taxShipping
168 taxesIncluded
169 timezone
170 updatedAt
171 weightUnit
172 zipCode
173 }
174 shopifyCreatedAt
175 shopifyUpdatedAt
176 sku
177 taxCode
178 taxable
179 title
180 updatedAt
181 weight
182 weightUnit
183 }
184 quiz {
185 id
186 state
187 body
188 createdAt
189 title
190 updatedAt
191 }
192 responses {
193 edges {
194 node {
195 id
196 state
197 conversionState
198 createdAt
199 email
200 quiz {
201 id
202 state
203 body
204 createdAt
205 title
206 updatedAt
207 }
208 result {
209 id
210 state
211 body
212 createdAt
213 imageUrl
214 updatedAt
215 }
216 updatedAt
217 }
218 }
219 }
220 updatedAt
221 }
222 }
223}
Variables
json
{
"id": "some-id",
"result": {}
}
Output

Update returns the Result. 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 UpdateResultResult {
success: Boolean!
errors: [ExecutionError!]
result: Result
}

Result Delete

The Delete action destroys the record.

Input

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

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

Result Create

The Create action transitions a Result from Start to Created.

Input

Create accepts the following input parameters:

Create Input Data
1export interface CreateResultInput {
2 answers?: (AnswerHasManyInput | null)[];
3
4 body?: (Scalars["String"] | null) | null;
5
6 quiz?: QuizBelongsToInput | null;
7
8 imageUrl?: (Scalars["String"] | null) | null;
9
10 responses?: (ResponseHasManyInput | null)[];
11
12 productSuggestion?: ShopifyProductVariantBelongsToInput | null;
13}
14
15export interface CreateResultArguments {
16 result?: CreateResultInput | null;
17}
1input CreateResultInput {
2 answers: [AnswerHasManyInput]
3 body: String
4 quiz: QuizBelongsToInput
5 imageUrl: String
6 responses: [ResponseHasManyInput]
7 productSuggestion: ShopifyProductVariantBelongsToInput
8}
9
10input CreateResultArguments {
11 result: CreateResultInput
12}
Example Create Invocation
1const resultRecord = await api.result.create({
2 result: {
3 // field values for Result
4 },
5});
6console.log(resultRecord.id); //=> a string
1const [result, createResult] = useAction(api.result.create);
2const { data, error, fetching } = result;
3await createResult({
4 result: {
5 // field values for Result
6 },
7});
8console.log(data?.id); //=> a string
1mutation ($result: CreateResultInput) {
2 createResult(result: $result) {
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 result {
18 __typename
19 id
20 state
21 answers {
22 edges {
23 node {
24 id
25 state
26 createdAt
27 question {
28 id
29 state
30 body
31 createdAt
32 imageUrl
33 required
34 sequence
35 title
36 updatedAt
37 }
38 response {
39 id
40 state
41 conversionState
42 createdAt
43 email
44 updatedAt
45 }
46 result {
47 id
48 state
49 body
50 createdAt
51 imageUrl
52 updatedAt
53 }
54 sequence
55 text
56 updatedAt
57 }
58 }
59 }
60 body
61 createdAt
62 imageUrl
63 productSuggestion {
64 id
65 state
66 barcode
67 compareAtPrice
68 createdAt
69 fulfillmentService
70 grams
71 inventoryManagement
72 inventoryPolicy
73 inventoryQuantity
74 inventoryQuantityAdjustment
75 oldInventoryQuantity
76 option1
77 option2
78 option3
79 position
80 presentmentPrices
81 price
82 product {
83 id
84 state
85 body
86 createdAt
87 handle
88 productType
89 publishedAt
90 publishedScope
91 shopifyCreatedAt
92 shopifyUpdatedAt
93 tags
94 templateSuffix
95 title
96 updatedAt
97 vendor
98 }
99 productImage {
100 id
101 state
102 createdAt
103 height
104 position
105 shopifyCreatedAt
106 shopifyUpdatedAt
107 source
108 updatedAt
109 width
110 }
111 requiresShipping
112 shop {
113 id
114 state
115 accessToken
116 address1
117 address2
118 checkoutApiSupported
119 city
120 cookieConsentLevel
121 country
122 countryCode
123 countryName
124 countyTaxes
125 createdAt
126 currency
127 customerEmail
128 domain
129 eligibleForCardReaderGiveaway
130 eligibleForPayments
131 email
132 enabledPresentmentCurrencies
133 finances
134 forceSsl
135 googleAppsDomain
136 googleAppsLoginEnabled
137 grantedScopes
138 hasDiscounts
139 hasGiftCards
140 hasStorefront
141 ianaTimezone
142 installedViaApiKey
143 latitude
144 longitude
145 moneyFormat
146 moneyInEmailsFormat
147 moneyWithCurrencyFormat
148 moneyWithCurrencyInEmailsFormat
149 multiLocationEnabled
150 myshopifyDomain
151 name
152 passwordEnabled
153 phone
154 planDisplayName
155 planName
156 preLaunchEnabled
157 primaryLocale
158 province
159 provinceCode
160 registeredWebhooks
161 requiresExtraPaymentsAgreement
162 setupRequired
163 shopOwner
164 shopifyCreatedAt
165 shopifyUpdatedAt
166 source
167 taxShipping
168 taxesIncluded
169 timezone
170 updatedAt
171 weightUnit
172 zipCode
173 }
174 shopifyCreatedAt
175 shopifyUpdatedAt
176 sku
177 taxCode
178 taxable
179 title
180 updatedAt
181 weight
182 weightUnit
183 }
184 quiz {
185 id
186 state
187 body
188 createdAt
189 title
190 updatedAt
191 }
192 responses {
193 edges {
194 node {
195 id
196 state
197 conversionState
198 createdAt
199 email
200 quiz {
201 id
202 state
203 body
204 createdAt
205 title
206 updatedAt
207 }
208 result {
209 id
210 state
211 body
212 createdAt
213 imageUrl
214 updatedAt
215 }
216 updatedAt
217 }
218 }
219 }
220 updatedAt
221 }
222 }
223}
Variables
json
{
"result": {}
}
Output

Create returns the Result. 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 CreateResultResult {
success: Boolean!
errors: [ExecutionError!]
result: Result
}

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 resultRecord = await api.result.create({
2 result: {
3 body: "bodyValue",
4 answers: {
5 // Updates existing `answer` record
6 // (`id` of record required),
7 // and links it to result.
8 update: {
9 id: "123",
10 text: "answersTextValue",
11 },
12 },
13 },
14});
15console.log(resultRecord.id); //=> a string
1const [result, createResult] = useAction(api.result.create);
2const { data, error, fetching } = result;
3await createResult({
4 result: {
5 body: "bodyValue",
6 answers: {
7 // Updates existing `answer` record
8 // (`id` of record required),
9 // and links it to result.
10 update: {
11 id: "123",
12 text: "answersTextValue",
13 },
14 },
15 },
16});
17console.log(data?.id); //=> a string
1mutation ($result: CreateResultInput) {
2 createResult(result: $result) {
3 success
4 errors {
5 message
6 }
7 result {
8 id
9 body
10 answers {
11 edges {
12 node {
13 id
14 }
15 }
16 }
17 }
18 }
19}
Variables
json
1{
2 "body": "bodyValue",
3 "answers": {
4 "update": {
5 "id": "123",
6 "text": "answersTextValue"
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 resultRecord = await api.result.create({
2 result: {
3 body: "bodyValue",
4 answers: {
5 // Creates `answer` record,
6 // linked to result.
7 create: {
8 text: "answersTextValue",
9 },
10 },
11 },
12});
13console.log(resultRecord.id); //=> a string
1const [result, createResult] = useAction(api.result.create);
2const { data, error, fetching } = result;
3await createResult({
4 result: {
5 body: "bodyValue",
6 answers: {
7 // Creates `answer` record,
8 // linked to result.
9 create: {
10 text: "answersTextValue",
11 },
12 },
13 },
14});
15console.log(data?.id); //=> a string
1mutation ($result: CreateResultInput) {
2 createResult(result: $result) {
3 success
4 errors {
5 message
6 }
7 result {
8 id
9 body
10 answers {
11 edges {
12 node {
13 id
14 }
15 }
16 }
17 }
18 }
19}
Variables
json
1{
2 "body": "bodyValue",
3 "answers": {
4 "create": {
5 "text": "answersTextValue"
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 answerRecord = await api.answer.create({
2 answer: {
3 text: "textValue",
4 // Links answer to existing
5 // parent `result` record.
6 result: {
7 _link: "123",
8 },
9 },
10});
11console.log(answerRecord.id); //=> a string
1const [result, createAnswer] = useAction(api.answer.create);
2const { data, error, fetching } = result;
3await createAnswer({
4 answer: {
5