Describe the bug
In generated schema for models that has @searchable attribute there are generated search* methods with invalid nextToken type - Int. These methods returns nextToken as Long (encoded as String) so one cannot continue searching with this token because of following error returned from GraphQL API endpoint:
{
"message": "Variable 'nextToken' has an invalid value. Expected type 'Int' but was 'Long'."
}
To Reproduce
Steps to reproduce the behavior:
type Customer
@model(mutations: { create: "createCustomer", update: "updateCustomer" })
@searchable
@auth(rules: [
{ allow: groups, groups: ["Administrators"] },
]) {
data: AWSJSON
isArchived: Boolean!
createdAt: AWSDateTime
id: ID!
name: String!
address: String
description: String
phone: String
email: String
}
searchCustomers(
filter: SearchableCustomerFilterInput,
sort: SearchableCustomerSortInput,
limit: Int,
nextToken: Int
): SearchableCustomerConnection
{
"searchCustomers": {
"__typename": "SearchableCustomerConnection",
"items": [ ... ],
"nextToken": "1547964054859"
}
}
{
"message": "Variable 'nextToken' has an invalid value. Expected type 'Int' but was 'Long'."
}
Expected behavior
Something is wrong with generated schema AND typescript (I'm using Angular) code. Search* method returns very long number in response as a string but expects Int in next call.
I did hours of research on this today. I think the implementation is incorrect.
The code is assuming that search works the same way as list and that the entry in sort can be used as a nextToken.
That is how DynamoDB backend works, but not how the ElasticSearch backend works.
ElasticSearch implements from and it should be an offset. i.e. if you want the 11-20th records you would set from to 11. Similar to SQL OFFSET
I think nextToken should be renamed to offset or from for a search and the code trying to add nextToken to the response should be removed.
Could be wrong, but hust using ```{ limit: pageSize, nextToken: page*pageSize } works for me, and also makes sense that it is an int.
The above isn't a great description but I'm in a rush at the moment. If it's not clear I can provide more detail later
Thank you @johnf! To see a detailed implementation would be great.
@johnf or @Futhark is there a work around for this issue? We鈥檝e run into it as well.
@sakhmedbayev @lookitsatravis, @johnf workaround works great. Here is how I have implemented it (in Angular 7):
constructor (private apiService: APIService) {}
private page = 0;
public allData = [];
loadSearchData() {
let filter = ...
let sort = ...
const pageSize = 10;
const token = pageSize * this.page;
this.apiService.SearchSomething(filter, sort, pageSize, token).then(res=>{
this.allData = [...this.allData, ...res.items];
this.page += 1;
}).catch(err=>console.error(err))
}
checkIfScrolledToBottom() {
//function that checks if the user has scrolled to the bottom and then results in running loadSearchData again (in reality implemented with hostlistener for scroll events)
this.loadSearchData();
}
Same workaround here, but I'm using a different pattern for storing the 'next page' in the response itself. It does seem to work - looks like @johnf's suspicion is correct.
export interface Identifiable {
id:string
}
export interface CompanySummary extends Identifiable {
companyName:string;
}
export type Companies = {
result:CompanySummary[];
nextPage?:Observable<Companies>
}
searchCompanies(nameContaining: string, limit: number, page: number = 0): Observable<Companies> {
let p = this.api.SearchCompanyRows({
name: {
matchPhrasePrefix: nameContaining
},
}, null, limit, page*limit)
return from(p).pipe(
map((value):Companies => {
let result = value.items.map(item => {
return {
companyName: item.name,
id: item.id
}
})
let next = value.items.length < limit
? null
: this.searchCompanies(nameContaining,limit, page+1)
return {
nextPage: next,
result: result
}
})
)
}
@Futhark, any update on the above responses?
@jordanranz The workaround works, but this is still an open bug - nextToken should be renamed as @johnf suggests.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
This issue has been automatically closed because of inactivity. Please open a new issue if are still encountering problems.
Most helpful comment
I did hours of research on this today. I think the implementation is incorrect.
The code is assuming that search works the same way as list and that the entry in sort can be used as a nextToken.
That is how DynamoDB backend works, but not how the ElasticSearch backend works.
ElasticSearch implements from and it should be an offset. i.e. if you want the 11-20th records you would set from to 11. Similar to SQL
OFFSETI think nextToken should be renamed to offset or from for a search and the code trying to add nextToken to the response should be removed.
Could be wrong, but hust using ```{ limit: pageSize, nextToken: page*pageSize } works for me, and also makes sense that it is an int.
The above isn't a great description but I'm in a rush at the moment. If it's not clear I can provide more detail later