Skip to content

Typescript queries with raw: true should not return model instances #12575

Closed
@JacobLey

Description

@JacobLey

Issue Description

Currently when running a query with a model in Typescript, the result(s) are instances of the model.
e.g.

import { Model } from 'sequelize';

class Foo extends Model {};

async () => {
    // Foo.findAll() returns Promise<Foo[]>
    const foos: Foo[] = await Foo.findAll();
};

This is expected and ideal behavior.
However when running a query with raw: true (https://sequelize.org/master/manual/raw-queries.html) the response is very much not an instance of the model (what it is is up for discussion in this issue).

The typing for queries that support raw should support returning non-model responses.

async () => {
    const foos: = await Foo.findAll({
        attributes: [[fn('RAND'), 'random']],
        raw: true,
    });
    
    foos.forEach(foo => {
        // Typescript fails on `random` is not on `Foo`
        console.log(foo.random);
    });
};

What was unclear/insufficient/not covered in the documentation

Presently, all Model query methods that support {raw: true} still declare they return the model instance, when raw queries are explicitly not instances.

So regular model attributes like get are not even available (which are used as a workaround for custom attributes on non-raw results).

If possible: Provide some suggestion on how we can enhance the docs

Allow type parameters on methods that support raw: true to return a custom type, defaulting to the models raw attributes.

As an example, below is the existing definition for findAll: https://github.com/sequelize/sequelize/blob/v6/types/lib/model.d.ts#L1826

  public static findAll<M extends Model>(
    this: ModelStatic<M>,
    options?: FindOptions<M['_attributes']>): Promise<M[]>;

If we added another method definition that explicitly declared when raw: true to return a type parameter, it could correctly handle typing raw queries:

public static findAll<M extends Model>(
    this: ModelStatic<M>,
    options?: FindOptions<M['_attributes']> & { raw?: false }): Promise<M[]>;
  public static findAll<M extends Model, R extends any = M['_attributes']>(
    this: ModelStatic<M>,
    options?: FindOptions<M['_attributes']> & { raw: true }): Promise<R[]>;

The example query above could now be supported as:

Foo.findAll<Foo, { random: number }>({
   attributes: [fn('RAND'), 'random'],
   raw: true,
})

Additional context

If there is another known method (or suggestions) for typing raw queries I'd appreciate the advice.

I know it is possible to just run the query as raw: false and use getters to load the custom attributes, but I believe raw queries serve their purpose when the extra noise of model instances is unnecessary. Not to mention the current typing is objectively wrong in this case.

Issue Template Checklist

Is this issue 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
  • I don't know.

Would you be willing to resolve this issue by submitting a Pull Request?

Happy to make an actual PR with my suggested findAll() as well as a couple others (possibly findOne + findByPk?) if the solution sounds correct

  • 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    released on @v7typescriptFor issues and PRs. Things that involve typescript, such as typings and intellisense.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions