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

feat(model): add option to return raw query #11881

Closed
wants to merge 2 commits into from

Conversation

seromenho
Copy link

@seromenho seromenho commented Jan 27, 2020

Pull Request check-list

Please make sure to review and check all of these items:

  • Does npm run test or npm run test-DIALECT pass with this change (including linting)?
  • Does the description below contain a link to an existing issue (Closes #[issue]) or a description of the issue you are solving?
  • Have you added new tests to prevent regressions?
  • Is a documentation update included (if this change modifies existing APIs, or introduces new ones)?
  • Did you update the typescript typings accordingly (if applicable)?
  • Did you follow the commit message conventions explained in CONTRIBUTING.md?

Description of change

Usage

User.beforeFind(() => {
  console.log('I will be skipped');
});

const sql = await User.findAll({getRawSql: true})
console.log(sql); //  {query: "SELECT ....."}

Implements #2325

I'll come back to this and improve the PR description and add some tests if someone confirms this is a good direction.
Thanks

@seromenho seromenho changed the title Feat/get raw sql WIP: Feat/get raw sql Jan 27, 2020
@codecov
Copy link

codecov bot commented Jan 27, 2020

Codecov Report

❗ No coverage uploaded for pull request base (main@51bc05a). Click here to learn what that means.
The diff coverage is n/a.

❗ Current head 271c08b differs from pull request most recent head ddb5d73. Consider uploading reports for the commit ddb5d73 to get more accurate results
Impacted file tree graph

@@           Coverage Diff           @@
##             main   #11881   +/-   ##
=======================================
  Coverage        ?   96.25%           
=======================================
  Files           ?       94           
  Lines           ?     9214           
  Branches        ?        0           
=======================================
  Hits            ?     8869           
  Misses          ?      345           
  Partials        ?        0           

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 51bc05a...ddb5d73. Read the comment docs.

@jdgriffith
Copy link

This would be a great addition that our organization would use immediately. Any chance we can get feedback on whether this is a good approach?

@tjwhitfield-lilly
Copy link

@dleo9307 What is the timeframe on this getting merged / released?

@@ -975,8 +975,13 @@ class QueryInterface {

async select(model, tableName, optionsArg) {
const options = { ...optionsArg, type: QueryTypes.SELECT, model };
const query = this.QueryGenerator.selectQuery(tableName, options, model);
Copy link

Choose a reason for hiding this comment

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

looks like this should be const query = this.queryGenerator.selectQuery(tableName, options, model);

dleo9307
dleo9307 previously approved these changes Oct 7, 2021
@sdepold
Copy link
Member

sdepold commented Oct 24, 2021

Hey there :)

First of all: Thanks a bunch for your contribution to Sequelize! Much appreciated!
Second: Unfortunately we haven't had the chance to look into this ever since you created it. Sorry for that!

A couple of months ago, we have switched from master to main branch as our primary development branch and hence this PR is now outdated :(

If you still think this change is making sense, please consider recreating the PR against main. Thanks in advance and sorry for the additional work.

✌️

@jdgriffith
Copy link

@sdepold Can you comment on whether this is the right approach for retrieving the raw sql? It feels like there has been hardly any discussion from maintainers regarding this PR (maybe I'm missing something). We would love to get this merged into a mainline branch but curious what the likelihood is of that happening.

@seromenho seromenho changed the base branch from master to main October 25, 2021 10:58
@seromenho seromenho dismissed dleo9307’s stale review October 25, 2021 10:58

The base branch was changed.

@seromenho
Copy link
Author

seromenho commented Oct 25, 2021

@sdepold updated the PR and it's now against main branch. 👍

@github-actions github-actions bot added the stale label Nov 3, 2021
@fzn0x fzn0x added type: feature For issues and PRs. For new features. Never breaking changes. and removed stale labels Nov 4, 2021
@jdgriffith
Copy link

Do I dare hope this is about to make it into sequelize?! 😍

@sdepold
Copy link
Member

sdepold commented Nov 18, 2021

if it is WIP: Can we maybe convert it into a draft PR?

@sdepold
Copy link
Member

sdepold commented Nov 18, 2021

fwiw: I just rebased. main is now including some bits and pieces about typescript. it shouldn't make a huge diff

Copy link
Member

@Keimeno Keimeno left a comment

Choose a reason for hiding this comment

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

Thanks for your contribution @seromenho, and sorry for the late response!

I've marked two things that I would change about this PR.

There's also a problem inside our lib/model.js, where we make use of the select method.

sequelize/lib/model.js

Lines 1754 to 1770 in 4071378

const results = await this.queryInterface.select(this, this.getTableName(selectOptions), selectOptions);
if (options.hooks) {
await this.runHooks('afterFind', results, options);
}
//rejectOnEmpty mode
if (_.isEmpty(results) && options.rejectOnEmpty) {
if (typeof options.rejectOnEmpty === 'function') {
throw new options.rejectOnEmpty();
}
if (typeof options.rejectOnEmpty === 'object') {
throw options.rejectOnEmpty;
}
throw new sequelizeErrors.EmptyResultError();
}
return await Model._findSeparate(results, options);

We have a problem here because our result is processed further, we will have to check for these scenarios as well. An early return might be a good solution

Also, I'm unsure if we should limit this option for findAndCountAll, findAll and findOne queries, but it might as well make sense to separate this into multiple PRs

@@ -90,7 +90,10 @@ const Hooks = {

async runHooks(hooks, ...hookArgs) {
if (!hooks) throw new Error('runHooks requires at least 1 argument');

// Skip hooks if we are only getting raw SQL
if (hookArgs[0] && typeof hookArgs[0] === 'object' && hookArgs[0].getRawSql) {
Copy link
Member

@Keimeno Keimeno Nov 21, 2021

Choose a reason for hiding this comment

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

Hooks can also modify the resulting query, such as beforeFind. I think it's best if we modify our lib/model.js to ignore specific hooks.

@@ -949,11 +949,12 @@ class QueryInterface {

async select(model, tableName, optionsArg) {
const options = { ...optionsArg, type: QueryTypes.SELECT, model };
const query = this.queryGenerator.selectQuery(tableName, options, model);
if (options.getRawSql) {
Copy link
Member

@Keimeno Keimeno Nov 21, 2021

Choose a reason for hiding this comment

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

I'm unsure if getRawSql is the best name for this option, I would probably go with something like queryOnly, getQuery, query or something else that more universally expresses what the expected return type is.

@Keimeno Keimeno marked this pull request as draft November 21, 2021 14:54
@Keimeno Keimeno changed the title WIP: Feat/get raw sql feat(model): add option to return raw query Nov 21, 2021
@ephys
Copy link
Member

ephys commented Apr 7, 2022

One note I have about this PR is that we should avoid having different return types for our functions. It makes typing them and using them with TypeScript much more complicated.

Instead, let's add a new method that does this. Maybe Model.getFindQuery, Model.findAll.getQuery(), or let's keep it as a method on the Query Builder? #394

@piotr-pawlowski
Copy link

When do you plan to merge this PR? We really need that feature.

@github-actions github-actions bot removed the stale label Apr 8, 2022
@ephys
Copy link
Member

ephys commented Dec 8, 2022

I'm closing this issue because as indicated here, we're working on making QueryGenerator a public API instead, combined with this other solution and this one

@ephys ephys closed this Dec 8, 2022
@cr0mbly
Copy link

cr0mbly commented Apr 26, 2024

I know there was talks about making the QueryGenerator public, but it's been a few years. If this isn't going to be the case we can institute the above PR. Would love to use this natively.

@jdgriffith
Copy link

A part of me is sad to look back and see my first comment on this thread was four years ago.

I think it's worth merging this PR, assuming it's ready or can be modified easily, as a stop gap until new features or v7 arrives.

@Nick-Riggs
Copy link

I've needed this for years for different projects, and I've always monkey-patched it. It may not cover every case, but something to the effect of:

    const realQuery = sequelize.query.bind(sequelize);

    sequelize.query = async function (sql: string, options: QueryOptions) {
        if (options?.returnSqlOnly) {
            return sql;
        }

        return realQuery(sql, options);
    }

I hope to see it in the framework proper someday as well.

@jdgriffith
Copy link

@Nick-Riggs Our team has had to do something similar because we have a dynamic query layer based on the sequelize ORM.

@cr0mbly
Copy link

cr0mbly commented May 7, 2024

@ephys this seems like a pretty big want/need from the community, are we able to look at this again?

I Just note again most ORMs I've dealt with have offered easy exposure of the SQL they're building within the ORM builder itself, it'd be nice if sequlize kept to that convention:

### Rails
Model.all.to_sql
>>> "SELECT `models`.* FROM `models`" 

### Django
Model.objects.all().query()
>>> "SELECT `models`.* FROM `models`"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: feature For issues and PRs. For new features. Never breaking changes.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet