Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[HACKDAY] added populate method to Promise to chain off any load / find call #133

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

zgavin
Copy link
Collaborator

@zgavin zgavin commented Jun 28, 2021

not 100% on this being the right way to go, but it compiles and actually works 🙃

@zgavin zgavin force-pushed the populate-promises branch 2 times, most recently from 32f5971 to 451bf60 Compare June 29, 2021 19:25
export {};

declare global {
interface Promise<T> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I appreciate the creativity here :-) but yeah, I'm not comfortable with this level of prototype hacking, both a) outside of graphql-service, and b) these populate methods only allow to promises of entities and not all promises.

Copy link
Collaborator Author

@zgavin zgavin Jun 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

was thinking maybe we just provide the method definitions in their own interface and a helper function that would add the implementation to Promise.prototype. Then consumers could apply it globally on an opt in basis.

eg we'd define something like this:

export interface PromisePopulate<T> {
  populate<T extends Entity, H extends LoadHint<T>>(this: Promise<T>, hint: H): Promise<Loaded<T, H>>;
  ...
}
export function addPopulateToPromise() { Promise.prototype.populate = ... }

and then codebases that use joist could add this somewhere to get the behavior if they wanted:

declare global { interface Promise<T> extends PromisePopulate<T> {} }
addPopulateToPromise();

// When we load the author then try to load and populate through publisher
const em = newEntityManager();
const author = await em.load(Author, "a:1");
const publisher = await author.publisher.load().populate("images");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this is what we originally wanted to be author.publisher.load("images") but doesn't jive with TS?

Can you just the return type of Reference.load to Promise<...> & { populate: ... }, and then monkey-patch populate directly onto that single promise instead of the global Promise prototype?

I guess I wouldn't be surprised if, to do something like:

const promise = em.load(....);
promise.populate = ....
return promise;

We can't use async functions b/c the compiler/runtime rewriting of the function might create it's own promise, and not use the promise that we monkey-patched with a populate key.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iirc adding a Loaded or LoadHint anywhere in the definition of Reference or Collection resulted in circular reference compiler errors

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants