123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 |
- 'use strict';
- const uniq = require('lodash/uniq');
- const chai = require('chai');
- const expect = chai.expect;
- const Support = require('../../support');
- const dialect = Support.getTestDialect();
- const { DataTypes } = require('@sequelize/core');
- if (dialect.startsWith('postgres')) {
- describe('[POSTGRES Specific] QueryInterface', () => {
- beforeEach(function () {
- this.queryInterface = this.sequelize.queryInterface;
- });
- describe('fetchDatabaseVersion', () => {
- it('reports version', async function () {
- const res = await this.queryInterface.fetchDatabaseVersion();
- // check that result matches the expected version number format. example 9.5.4
- expect(res).to.match(/\d\.\d/);
- });
- });
- describe('renameFunction', () => {
- beforeEach(async function () {
- // ensure the function names we'll use don't exist before we start.
- // then setup our function to rename
- await this.queryInterface.dropFunction('rftest1', []).catch(() => {});
- await this.queryInterface.dropFunction('rftest2', []).catch(() => {});
- await this.queryInterface.createFunction(
- 'rftest1',
- [],
- 'varchar',
- 'plpgsql',
- "return 'testreturn';",
- {},
- );
- });
- it('renames a function', async function () {
- await this.queryInterface.renameFunction('rftest1', [], 'rftest2');
- const res = await this.sequelize.query('select rftest2();', {
- type: this.sequelize.QueryTypes.SELECT,
- });
- expect(res[0].rftest2).to.be.eql('testreturn');
- });
- });
- describe('createFunction', () => {
- beforeEach(async function () {
- // make sure we don't have a pre-existing function called create_job
- // this is needed to cover the edge case of afterEach not getting called because of an unexpected issue or stopage with the
- // test suite causing a failure of afterEach's cleanup to be called.
- await this.queryInterface
- .dropFunction('create_job', [{ type: 'varchar', name: 'test' }])
- // suppress errors here. if create_job doesn't exist thats ok.
- .catch(() => {});
- });
- after(async function () {
- // cleanup
- await this.queryInterface
- .dropFunction('create_job', [{ type: 'varchar', name: 'test' }])
- // suppress errors here. if create_job doesn't exist thats ok.
- .catch(() => {});
- });
- it('creates a stored procedure', async function () {
- const body = 'return test;';
- const options = {};
- // make our call to create a function
- await this.queryInterface.createFunction(
- 'create_job',
- [{ type: 'varchar', name: 'test' }],
- 'varchar',
- 'plpgsql',
- body,
- options,
- );
- // validate
- const res = await this.sequelize.query("select create_job('test');", {
- type: this.sequelize.QueryTypes.SELECT,
- });
- expect(res[0].create_job).to.be.eql('test');
- });
- it('treats options as optional', async function () {
- const body = 'return test;';
- // run with null options parameter
- await this.queryInterface.createFunction(
- 'create_job',
- [{ type: 'varchar', name: 'test' }],
- 'varchar',
- 'plpgsql',
- body,
- null,
- );
- // validate
- const res = await this.sequelize.query("select create_job('test');", {
- type: this.sequelize.QueryTypes.SELECT,
- });
- expect(res[0].create_job).to.be.eql('test');
- });
- it('produces an error when missing expected parameters', async function () {
- const body = 'return 1;';
- const options = {};
- await Promise.all([
- // requires functionName
- expect(
- this.queryInterface.createFunction(
- null,
- [{ name: 'test' }],
- 'integer',
- 'plpgsql',
- body,
- options,
- ),
- ).to.be.rejectedWith(
- /createFunction missing some parameters. Did you pass functionName, returnType, language and body/,
- ),
- // requires Parameters array
- expect(
- this.queryInterface.createFunction(
- 'create_job',
- null,
- 'integer',
- 'plpgsql',
- body,
- options,
- ),
- ).to.be.rejectedWith(/function parameters array required/),
- // requires returnType
- expect(
- this.queryInterface.createFunction(
- 'create_job',
- [{ type: 'varchar', name: 'test' }],
- null,
- 'plpgsql',
- body,
- options,
- ),
- ).to.be.rejectedWith(
- /createFunction missing some parameters. Did you pass functionName, returnType, language and body/,
- ),
- // requires type in parameter array
- expect(
- this.queryInterface.createFunction(
- 'create_job',
- [{ name: 'test' }],
- 'integer',
- 'plpgsql',
- body,
- options,
- ),
- ).to.be.rejectedWith(/function or trigger used with a parameter without any type/),
- // requires language
- expect(
- this.queryInterface.createFunction(
- 'create_job',
- [{ type: 'varchar', name: 'test' }],
- 'varchar',
- null,
- body,
- options,
- ),
- ).to.be.rejectedWith(
- /createFunction missing some parameters. Did you pass functionName, returnType, language and body/,
- ),
- // requires body
- expect(
- this.queryInterface.createFunction(
- 'create_job',
- [{ type: 'varchar', name: 'test' }],
- 'varchar',
- 'plpgsql',
- null,
- options,
- ),
- ).to.be.rejectedWith(
- /createFunction missing some parameters. Did you pass functionName, returnType, language and body/,
- ),
- ]);
- });
- it('overrides a function', async function () {
- const first_body = "return 'first';";
- const second_body = "return 'second';";
- // create function
- await this.queryInterface.createFunction(
- 'create_job',
- [{ type: 'varchar', name: 'test' }],
- 'varchar',
- 'plpgsql',
- first_body,
- null,
- );
- // override
- await this.queryInterface.createFunction(
- 'create_job',
- [{ type: 'varchar', name: 'test' }],
- 'varchar',
- 'plpgsql',
- second_body,
- null,
- { force: true },
- );
- // validate
- const res = await this.sequelize.query("select create_job('abc');", {
- type: this.sequelize.QueryTypes.SELECT,
- });
- expect(res[0].create_job).to.be.eql('second');
- });
- it('produces an error when options.variables is missing expected parameters', function () {
- const body = 'return 1;';
- expect(
- this.queryInterface.createFunction('test_func', [], 'integer', 'plpgsql', body, [], {
- variables: 100,
- }),
- ).to.be.rejectedWith(/expandFunctionVariableList: function variables must be an array/);
- expect(
- this.queryInterface.createFunction('test_func', [], 'integer', 'plpgsql', body, [], {
- variables: [{ name: 'myVar' }],
- }),
- ).to.be.rejectedWith(/function variable must have a name and type/);
- expect(
- this.queryInterface.createFunction('test_func', [], 'integer', 'plpgsql', body, [], {
- variables: [{ type: 'integer' }],
- }),
- ).to.be.rejectedWith(/function variable must have a name and type/);
- });
- it('uses declared variables', async function () {
- await this.sequelize.query('DROP FUNCTION IF EXISTS add_one;');
- const body = 'RETURN myVar + 1;';
- const options = { variables: [{ type: 'integer', name: 'myVar', default: 100 }] };
- await this.queryInterface.createFunction(
- 'add_one',
- [],
- 'integer',
- 'plpgsql',
- body,
- [],
- options,
- );
- const res = await this.sequelize.query('select add_one();', {
- type: this.sequelize.QueryTypes.SELECT,
- });
- expect(res[0].add_one).to.be.eql(101);
- });
- });
- describe('dropFunction', () => {
- beforeEach(async function () {
- const body = 'return test;';
- const options = {};
- // make sure we have a droptest function in place.
- await this.queryInterface
- .createFunction(
- 'droptest',
- [{ type: 'varchar', name: 'test' }],
- 'varchar',
- 'plpgsql',
- body,
- options,
- )
- // suppress errors.. this could fail if the function is already there.. thats ok.
- .catch(() => {});
- });
- it('can drop a function', async function () {
- // call drop function
- await this.queryInterface.dropFunction('droptest', [{ type: 'varchar', name: 'test' }]);
- await expect(
- // now call the function we attempted to drop.. if dropFunction worked as expect it should produce an error.
- this.sequelize.query("select droptest('test');", {
- type: this.sequelize.QueryTypes.SELECT,
- }),
- // test that we did get the expected error indicating that droptest was properly removed.
- ).to.be.rejectedWith(/.*function droptest.* does not exist/);
- });
- it('produces an error when missing expected parameters', async function () {
- await Promise.all([
- expect(this.queryInterface.dropFunction()).to.be.rejectedWith(/.*requires functionName/),
- expect(this.queryInterface.dropFunction('droptest')).to.be.rejectedWith(
- /.*function parameters array required/,
- ),
- expect(
- this.queryInterface.dropFunction('droptest', [{ name: 'test' }]),
- ).to.be.rejectedWith(/.*function or trigger used with a parameter without any type/),
- ]);
- });
- });
- describe('indexes', () => {
- beforeEach(async function () {
- await this.queryInterface.dropTable('Group');
- await this.queryInterface.createTable('Group', {
- username: DataTypes.STRING,
- isAdmin: DataTypes.BOOLEAN,
- from: DataTypes.STRING,
- });
- });
- it('supports newlines', async function () {
- await this.queryInterface.addIndex(
- 'Group',
- [
- this.sequelize.literal(`(
- CASE "username"
- WHEN 'foo' THEN 'bar'
- ELSE 'baz'
- END
- )`),
- ],
- { name: 'group_username_case' },
- );
- const indexes = await this.queryInterface.showIndex('Group');
- const indexColumns = uniq(indexes.map(index => index.name));
- expect(indexColumns).to.include('group_username_case');
- });
- it('adds, reads and removes a named functional index to the table', async function () {
- await this.queryInterface.addIndex(
- 'Group',
- [this.sequelize.fn('lower', this.sequelize.col('username'))],
- {
- name: 'group_username_lower',
- },
- );
- const indexes0 = await this.queryInterface.showIndex('Group');
- const indexColumns0 = uniq(indexes0.map(index => index.name));
- expect(indexColumns0).to.include('group_username_lower');
- await this.queryInterface.removeIndex('Group', 'group_username_lower');
- const indexes = await this.queryInterface.showIndex('Group');
- const indexColumns = uniq(indexes.map(index => index.name));
- expect(indexColumns).to.be.empty;
- });
- });
- });
- }
|