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

[Draft RFC] Using Op.* as functions on top of keys #13

Open
2 of 6 tasks
ephys opened this issue Sep 1, 2020 · 20 comments
Open
2 of 6 tasks

[Draft RFC] Using Op.* as functions on top of keys #13

ephys opened this issue Sep 1, 2020 · 20 comments
Assignees
Labels
rfc Request for comments regarding breaking or large changes

Comments

@ephys
Copy link
Member

ephys commented Sep 1, 2020

Feature Description

Is your feature request related to a problem? Please describe.

I've personally never liked the ergonomics of having to use sequelize operators as keys for an object.
The following code

const where = { id: { [Op.notIn]: blockList } };

feels easier to read when written like this:

const where = { id: Op.notIn(blockList) };

Describe the solution you'd like

We could make it possible to use Op.* as both object keys and functions using toPrimitive. That would make both snippets of code above valid.

Proof of concept:

const symbolNotIn = Symbol('notIn');

function notIn(val) {
  return { [symbolNotIn]: val };
}

notIn[Symbol.toPrimitive] = () => {
  return symbolNotIn;
}

console.log(notIn([1, 2]));        // output: { [Symbol(notIn)]: [1, 2] }
console.log({ [notIn]: [1, 2] });  // output: { [Symbol(notIn)]: [1, 2] }

export const Op = {
  // ...
  notIn,
  // ...
};

Why should this be in Sequelize

I believe this would make the usage of operators easier to read and understand.

Describe alternatives/workarounds you've considered

If using Symbol.toPrimitive feels too much like magic, those functions could be provided somewhere else. Sequelize.and, Sequelize.or, etc already exist.

Additional context

N/A

Feature Request Checklist

Is this feature dialect-specific?

  • No. This issue is relevant to Sequelize as a whole.
  • Yes. This issue only applies to the following dialect(s): XXX, YYY, ZZZ

Would you be willing to implement this feature by submitting a Pull Request?

  • Yes, I have the time and I know how to start.
  • Yes, I have the time but I don't know how to start, I would need guidance.
  • No, I don't have the time, although I believe I could do it if I had the time...
  • No, I don't have the time and I wouldn't even know how to start.
@github-actions
Copy link

This issue has been automatically marked as stale because it has been open for 7 days without activity. It will be closed if no further activity occurs. If this is still an issue, just leave a comment or remove the "stale" label. 🙂

@ephys
Copy link
Member Author

ephys commented Oct 31, 2021

still ready to work on this if interested :)

@github-actions
Copy link

This issue has been automatically marked as stale because it has been open for 14 days without activity. It will be closed if no further activity occurs within the next 14 days. If this is still an issue, just leave a comment or remove the "stale" label. 🙂

@WikiRik
Copy link
Member

WikiRik commented Nov 16, 2021

Hi @ephys
Thanks for willing to work on this, just submit a PR and then a maintainer can look into it!

@ephys
Copy link
Member Author

ephys commented Dec 7, 2021

Still intending on working on this but replacing the symbols with functions+Symbol.toPrimitive could be a breaking change for some users.

Is the main branch considered v7 or should I wait?

@WikiRik
Copy link
Member

WikiRik commented Dec 7, 2021

We do not have a v7 branch yet, but that might be good to have. @sdepold do you agree?

EDIT: Would be good if the v7 branch only accepts PRs in TypeScript so we don't have to convert those later

@sdepold
Copy link
Member

sdepold commented Dec 7, 2021

@sdepold
Copy link
Member

sdepold commented Dec 7, 2021

I'm not sure if we can have constraints on the language automatically somehow or if that is more a part of the review process

@sdepold
Copy link
Member

sdepold commented Dec 7, 2021

We can even setup automated releases of a v7 alpha version to npm if you think that makes sense

@ephys
Copy link
Member Author

ephys commented Dec 7, 2021

Thanks! I think it's possible to add a check that ensures touched files do not end in .js, but it's easier to add a note in the PR guidelines I think.

@sdepold
Copy link
Member

sdepold commented Dec 7, 2021

Are the PR guidelines taken from the target or the source branch? :D

@ephys
Copy link
Member Author

ephys commented Dec 7, 2021

I think from the target but only one way to find out :)

@sdepold
Copy link
Member

sdepold commented Dec 7, 2021

I guess since we will remove JS code, having it in the documentation might be more useful. What do you think ? sequelize/sequelize#13747

@ephys
Copy link
Member Author

ephys commented Dec 8, 2021

I'd say a simple note in CONTRIBUTING.md should be enough

@ephys ephys changed the title Using Op.* as functions on top of keys RFC: [v7] Using Op.* as functions on top of keys Dec 14, 2021
@ephys
Copy link
Member Author

ephys commented Dec 20, 2021

After working on a prototype, here are my findings:

TypeScript has very little support for Symbol.toPrimitive and while I did manage to make a prototype that can be used as both key and function call

Screenshot 2021-12-20 at 20 57 13

it breaks the typing of WhereOperator because the symbols are not unique anymore

Screenshot 2021-12-20 at 20 58 41

The following TypeScript issues are relevant:

I see three options going forward, none of which are particularly amazing:

  • Break WhereOperator typing. Doing { [Op.eq]: value } would not be type safe anymore, in favor of Op.eq(value) being type checked. (a no-go imo)
  • Wait until TypeScript has proper support for toPrimitive (likely to take years tbh).
  • Expose these functions separately. OpFn.eq (function) & Op.eq (symbol). (OpFn being a placeholder until I find a better name).

@ephys ephys changed the title Dec 23, 2021
@ephys ephys transferred this issue from sequelize/sequelize Dec 23, 2021
@ephys ephys changed the title [RFC]: Using Op.* as functions on top of keys [RFC] Using Op.* as functions on top of keys Dec 23, 2021
@ephys ephys added the rfc Request for comments regarding breaking or large changes label Dec 23, 2021
@ephys ephys self-assigned this Dec 23, 2021
@ephys
Copy link
Member Author

ephys commented Feb 7, 2022

Due to TypeScript not supporting Symbol.toPrimitive, maybe we could go the same route as Sequelize.and / Sequelize.or and expose a utility function for most / all operators:

import { notEqual } from 'sequelize';

User.findAll({
  where: { id: notEqual(5) }
});

That's a lot of extra exports with very generic names though :/

@sdepold
Copy link
Member

sdepold commented Feb 8, 2022

In general I like the proposal but would maybe not expose it via sequelize but maybe add a layer or nesting?

Import { Operators} from sequelize

Const { notEqual}=Operators

?

@ephys
Copy link
Member Author

ephys commented Feb 8, 2022

I agree, but Operators is very close to Op even though one is a namespace for functions, and the other one for symbols. I fear people might start using Operators as keys by accident

If we expose something like Operators, I think we should move Sequelize.and & Sequelize.or over to Operators too

This issue is frustrating. I have a solution that is almost working but it causes typescript to stop reporting errors with the current way of using operators:

image

@ephys
Copy link
Member Author

ephys commented Mar 30, 2022

I'm transfering RFCs to the main repo to gather feedback from users of the library, but I won't migrate this one because I'm not happy with it yet

@ephys ephys changed the title [RFC] Using Op.* as functions on top of keys [Draft RFC] Using Op.* as functions on top of keys Mar 30, 2022
@WikiRik
Copy link
Member

WikiRik commented Mar 30, 2022

Feel free to make a new issue that supersedes this one to have a cleaner discussion

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
rfc Request for comments regarding breaking or large changes
Projects
None yet
Development

No branches or pull requests

3 participants