When I try to extract out the non-UI logic into a separate function that returns the string data, it won't compile. It keeps telling me this when pointing to the line that's calling then new GetSchemaTable() function. If I put the call in an await call, it doesn't matter. I cannot find any combination of things that lets it compile. What the heck is the problem?
Unfortunately async methods are not meant to be used this way. You separated your code into GetSchemaTable and made it async - nothing wrong with that so far, that is the only way you can do this. However, this means when the code is being transpiled into JavaScript, it will be turned into an async JavaScript function. By definition all async JavaScript functions are promises (= TJSPromise), it doesn't matter that you gave it a different return value in Pascal: async function - JavaScript | MDN
The only option you have is to make GetSchemaTable return a TJSPromise that you resolve with a string, and await the promise in ListTables_btnClick (marked as async too like you did before), something similar to:
function TMain_form.GetSchemaTable(): TJSPromise;
begin
Result := TJSPromise.new(procedure (Resolve, Reject: TJSPromiseResolver) {$IFDEF PAS2jS}async{$ENDIF}
var
HttpRequest: TWebHttpRequest;
url: string;
req: TJSXMLHttpRequest;
begin
HttpRequest := TWebHttpRequest.Create(self);
try
URL := 'https://api.stellards.io/v1/schema/table?project='+PROJECT_ID;
HttpRequest.URL := URL;
HttpRequest.Command := httpGET;
HttpRequest.Headers.AddPair('Accept', 'application/json');
HttpRequest.Headers.AddPair('Content-Type', 'application/json');
HttpRequest.Headers.AddPair('Authorization', ACCESS_TOKEN);
req := TAwait.ExecP<TJSXMLHttpRequest>(HttpRequest.Perform());
Resolve(TJSJSON.stringify(TJSJSON.parse(string(req.response)), nil, 2));
finally
HttpRequest.Free;
end;
end);
end;
procedure TMain_form.ListTables_btnClick(Sender: TObject);
begin
Text_memo.Lines.Text := TAwait.ExecP<string>(GetSchemaTable());
end;
Actually, I don't think I've seen the use of stuff like this before:
function TMain_form.GetSchemaTable(): TJSPromise;
begin
Result := TJSPromise.new(procedure (Resolve, Reject: TJSPromiseResolver) {$IFDEF PAS2jS}async{$ENDIF}
var
HttpRequest: TWebHttpRequest;
. . .
begin
try
. . .
Resolve(TJSJSON.stringify(TJSJSON.parse(string(req.response)), nil, 2));
finally
HttpRequest.Free;
end;
end);
end;
The way I did it seems to have worked, with the OnClick method declared as async as well and using await to call GetSchemaTable, and having GetSchemaTable declared as async and return a string. Is that ok? (At least, I think that worked... I've tried a bunch of variations)
I want to have several of these access methods talking to the DB. It just seems like a lot of hoops to jump through. If I want to issue several requests in a row to the same URL, what's the simplest way to do it?
A function you want to await for should return a promise.
If you have a function returning a promise, you can await multiple calls to this promise function after each other.