123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438 |
- 'use strict';
- const chai = require('chai');
- const expect = chai.expect;
- const Support = require('../../support');
- const { DataTypes } = require('@sequelize/core');
- const {
- _validateIncludedElements,
- } = require('@sequelize/core/_non-semver-use-at-your-own-risk_/model-internals.js');
- const { beforeAll2 } = require('../../support');
- const expectsql = Support.expectsql;
- const current = Support.sequelize;
- const sql = current.dialect.queryGenerator;
- // Notice: [] will be replaced by dialect specific tick/quote character when there is not dialect specific expectation but only a default expectation
- describe('QueryGenerator#selectQuery with "order"', () => {
- function expectSelect(options, expectation) {
- const model = options.model;
- return expectsql(
- sql.selectQuery(options.table || (model && model.table), options, options.model),
- expectation,
- );
- }
- const vars = beforeAll2(() => {
- // models
- const User = Support.sequelize.define(
- 'User',
- {
- id: {
- type: DataTypes.INTEGER,
- primaryKey: true,
- autoIncrement: true,
- field: 'id',
- },
- name: {
- type: DataTypes.STRING,
- field: 'name',
- allowNull: false,
- },
- createdAt: {
- field: 'created_at',
- },
- updatedAt: {
- field: 'updated_at',
- },
- },
- {
- tableName: 'user',
- timestamps: true,
- },
- );
- const Project = Support.sequelize.define(
- 'Project',
- {
- id: {
- type: DataTypes.INTEGER,
- primaryKey: true,
- autoIncrement: true,
- field: 'id',
- },
- name: {
- type: DataTypes.STRING,
- field: 'name',
- allowNull: false,
- },
- createdAt: {
- field: 'created_at',
- },
- updatedAt: {
- field: 'updated_at',
- },
- },
- {
- tableName: 'project',
- timestamps: true,
- },
- );
- const ProjectUser = Support.sequelize.define(
- 'ProjectUser',
- {
- id: {
- type: DataTypes.INTEGER,
- primaryKey: true,
- autoIncrement: true,
- field: 'id',
- },
- userId: {
- type: DataTypes.INTEGER,
- field: 'user_id',
- allowNull: false,
- },
- projectId: {
- type: DataTypes.INTEGER,
- field: 'project_id',
- allowNull: false,
- },
- createdAt: {
- field: 'created_at',
- },
- updatedAt: {
- field: 'updated_at',
- },
- },
- {
- tableName: 'project_user',
- timestamps: true,
- },
- );
- const Task = Support.sequelize.define(
- 'Task',
- {
- id: {
- type: DataTypes.INTEGER,
- primaryKey: true,
- autoIncrement: true,
- field: 'id',
- },
- name: {
- type: DataTypes.STRING,
- field: 'name',
- allowNull: false,
- },
- projectId: {
- type: DataTypes.INTEGER,
- field: 'project_id',
- allowNull: false,
- },
- createdAt: {
- field: 'created_at',
- },
- updatedAt: {
- field: 'updated_at',
- },
- },
- {
- tableName: 'task',
- timestamps: true,
- },
- );
- const Subtask = Support.sequelize.define(
- 'Subtask',
- {
- id: {
- type: DataTypes.INTEGER,
- primaryKey: true,
- autoIncrement: true,
- field: 'id',
- },
- name: {
- type: DataTypes.STRING,
- field: 'name',
- allowNull: false,
- },
- taskId: {
- type: DataTypes.INTEGER,
- field: 'task_id',
- allowNull: false,
- },
- createdAt: {
- field: 'created_at',
- },
- updatedAt: {
- field: 'updated_at',
- },
- },
- {
- tableName: 'subtask',
- timestamps: true,
- },
- );
- // Relations
- User.belongsToMany(Project, {
- as: 'ProjectUserProjects',
- inverse: {
- as: 'ProjectUserUsers',
- },
- through: ProjectUser,
- foreignKey: 'user_id',
- otherKey: 'project_id',
- });
- Project.belongsToMany(User, {
- as: 'ProjectUserUsers',
- inverse: {
- as: 'ProjectUserProjects',
- },
- through: ProjectUser,
- foreignKey: 'project_id',
- otherKey: 'user_id',
- });
- Project.hasMany(Task, {
- as: 'Tasks',
- foreignKey: 'project_id',
- inverse: 'Project',
- });
- Task.belongsTo(Project, {
- as: 'Project',
- foreignKey: 'project_id',
- });
- Task.hasMany(Subtask, {
- as: 'Subtasks',
- foreignKey: 'task_id',
- inverse: 'Task',
- });
- Subtask.belongsTo(Task, {
- as: 'Task',
- foreignKey: 'task_id',
- });
- return { User, Project, ProjectUser, Task, Subtask };
- });
- it('supports "order"', () => {
- const { Project, Subtask, Task } = vars;
- expectSelect(
- {
- model: Subtask,
- attributes: ['id', 'name', 'createdAt'],
- include: _validateIncludedElements({
- include: [
- {
- association: Subtask.associations.Task,
- required: true,
- attributes: ['id', 'name', 'createdAt'],
- include: [
- {
- association: Task.associations.Project,
- required: true,
- attributes: ['id', 'name', 'createdAt'],
- },
- ],
- },
- ],
- model: Subtask,
- }).include,
- order: [
- // order with multiple simple association syntax with direction
- [
- {
- model: Task,
- as: 'Task',
- },
- {
- model: Project,
- as: 'Project',
- },
- 'createdAt',
- 'ASC',
- ],
- // order with multiple simple association syntax without direction
- [
- {
- model: Task,
- as: 'Task',
- },
- {
- model: Project,
- as: 'Project',
- },
- 'createdAt',
- ],
- // order with simple association syntax with direction
- [
- {
- model: Task,
- as: 'Task',
- },
- 'createdAt',
- 'ASC',
- ],
- // order with simple association syntax without direction
- [
- {
- model: Task,
- as: 'Task',
- },
- 'createdAt',
- ],
- // through model object as array with direction
- [Task, Project, 'createdAt', 'ASC'],
- // through model object as array without direction
- [Task, Project, 'createdAt'],
- // model object as array with direction
- [Task, 'createdAt', 'ASC'],
- // model object as array without direction
- [Task, 'createdAt'],
- // through association object as array with direction
- [Subtask.associations.Task, Task.associations.Project, 'createdAt', 'ASC'],
- // through association object as array without direction
- [Subtask.associations.Task, Task.associations.Project, 'createdAt'],
- // association object as array with direction
- [Subtask.associations.Task, 'createdAt', 'ASC'],
- // association object as array without direction
- [Subtask.associations.Task, 'createdAt'],
- // through association name order as array with direction
- ['Task', 'Project', 'createdAt', 'ASC'],
- // through association name as array without direction
- ['Task', 'Project', 'createdAt'],
- // association name as array with direction
- ['Task', 'createdAt', 'ASC'],
- // association name as array without direction
- ['Task', 'createdAt'],
- // main order as array with direction
- ['createdAt', 'ASC'],
- // main order as array without direction
- ['createdAt'],
- // main order as string
- 'createdAt',
- ],
- },
- {
- default:
- 'SELECT [Subtask].[id], [Subtask].[name], [Subtask].[createdAt], [Task].[id] AS [Task.id], [Task].[name] AS [Task.name], [Task].[created_at] AS [Task.createdAt], [Task->Project].[id] AS [Task.Project.id], [Task->Project].[name] AS [Task.Project.name], [Task->Project].[created_at] AS [Task.Project.createdAt] FROM [subtask] AS [Subtask] INNER JOIN [task] AS [Task] ON [Subtask].[task_id] = [Task].[id] INNER JOIN [project] AS [Task->Project] ON [Task].[project_id] = [Task->Project].[id] ORDER BY [Task->Project].[created_at] ASC, [Task->Project].[created_at], [Task].[created_at] ASC, [Task].[created_at], [Task->Project].[created_at] ASC, [Task->Project].[created_at], [Task].[created_at] ASC, [Task].[created_at], [Task->Project].[created_at] ASC, [Task->Project].[created_at], [Task].[created_at] ASC, [Task].[created_at], [Task->Project].[created_at] ASC, [Task->Project].[created_at], [Task].[created_at] ASC, [Task].[created_at], [Subtask].[created_at] ASC, [Subtask].[created_at], [Subtask].[created_at];',
- postgres:
- 'SELECT "Subtask"."id", "Subtask"."name", "Subtask"."createdAt", "Task"."id" AS "Task.id", "Task"."name" AS "Task.name", "Task"."created_at" AS "Task.createdAt", "Task->Project"."id" AS "Task.Project.id", "Task->Project"."name" AS "Task.Project.name", "Task->Project"."created_at" AS "Task.Project.createdAt" FROM "subtask" AS "Subtask" INNER JOIN "task" AS "Task" ON "Subtask"."task_id" = "Task"."id" INNER JOIN "project" AS "Task->Project" ON "Task"."project_id" = "Task->Project"."id" ORDER BY "Task->Project"."created_at" ASC, "Task->Project"."created_at", "Task"."created_at" ASC, "Task"."created_at", "Task->Project"."created_at" ASC, "Task->Project"."created_at", "Task"."created_at" ASC, "Task"."created_at", "Task->Project"."created_at" ASC, "Task->Project"."created_at", "Task"."created_at" ASC, "Task"."created_at", "Task->Project"."created_at" ASC, "Task->Project"."created_at", "Task"."created_at" ASC, "Task"."created_at", "Subtask"."created_at" ASC, "Subtask"."created_at", "Subtask"."created_at";',
- },
- );
- });
- it('supports random ordering', () => {
- const { Subtask } = vars;
- expectSelect(
- {
- model: Subtask,
- attributes: ['id', 'name'],
- order: [Support.sequelize.random()],
- },
- {
- ibmi: 'SELECT "id", "name" FROM "subtask" AS "Subtask" ORDER BY RAND()',
- mssql: 'SELECT [id], [name] FROM [subtask] AS [Subtask] ORDER BY RAND();',
- db2: 'SELECT "id", "name" FROM "subtask" AS "Subtask" ORDER BY RAND();',
- mariadb: 'SELECT `id`, `name` FROM `subtask` AS `Subtask` ORDER BY RAND();',
- mysql: 'SELECT `id`, `name` FROM `subtask` AS `Subtask` ORDER BY RAND();',
- postgres: 'SELECT "id", "name" FROM "subtask" AS "Subtask" ORDER BY RANDOM();',
- snowflake: 'SELECT "id", "name" FROM "subtask" AS "Subtask" ORDER BY RANDOM();',
- sqlite3: 'SELECT `id`, `name` FROM `subtask` AS `Subtask` ORDER BY RANDOM();',
- },
- );
- });
- describe('Invalid', () => {
- it('Error on invalid association', () => {
- const { Project, Subtask } = vars;
- return expect(
- Subtask.findAll({
- order: [[Project, 'createdAt', 'ASC']],
- }),
- ).to.eventually.be.rejectedWith(
- Error,
- 'Invalid Include received: no associations exist between "Subtask" and "Project"',
- );
- });
- it('Error on invalid structure', () => {
- const { Subtask, Task } = vars;
- return expect(
- Subtask.findAll({
- order: [[Subtask.associations.Task, 'createdAt', Task.associations.Project, 'ASC']],
- }),
- ).to.eventually.be.rejectedWith(Error, 'Unknown structure passed to order / group: Project');
- });
- it('Error when the order is a string', () => {
- const { Subtask } = vars;
- return expect(
- Subtask.findAll({
- order: 'i am a silly string',
- }),
- ).to.eventually.be.rejectedWith(
- Error,
- 'Order must be type of array or instance of a valid sequelize method.',
- );
- });
- it('Error when the order contains a `{raw: "..."}` object', () => {
- const { Subtask } = vars;
- return expect(
- Subtask.findAll({
- order: [
- {
- raw: 'this should throw an error',
- },
- ],
- }),
- ).to.eventually.be.rejectedWith(
- Error,
- 'The `{raw: "..."}` syntax is no longer supported. Use `sequelize.literal` instead.',
- );
- });
- it('Error when the order contains a `{raw: "..."}` object wrapped in an array', () => {
- const { Subtask } = vars;
- return expect(
- Subtask.findAll({
- order: [
- [
- {
- raw: 'this should throw an error',
- },
- ],
- ],
- }),
- ).to.eventually.be.rejectedWith(
- Error,
- 'The `{raw: "..."}` syntax is no longer supported. Use `sequelize.literal` instead.',
- );
- });
- });
- });
|