不要怂,就是干,撸起袖子干!

Commit 9b46f913 by Sushant Committed by GitHub

refactor: indexes and uniqueKey (#9589)

1 parent 9f2c9db8
......@@ -497,22 +497,6 @@ class QueryGenerator {
return _.template(query, this._templateSettings)(replacements);
}
nameIndexes(indexes, rawTablename) {
if (typeof rawTablename === 'object') {
// don't include schema in the index name
rawTablename = rawTablename.tableName;
}
return _.map(indexes, index => {
if (!index.hasOwnProperty('name')) {
const onlyAttributeNames = index.fields.map(field => typeof field === 'string' ? field : field.name || field.attribute);
index.name = Utils.underscore(rawTablename + '_' + onlyAttributeNames.join('_'));
}
return index;
});
}
/*
Returns an add index query.
Parameters:
......@@ -539,17 +523,6 @@ class QueryGenerator {
options.fields = attributes;
}
// Backwards compatability
if (options.indexName) {
options.name = options.indexName;
}
if (options.indicesType) {
options.type = options.indicesType;
}
if (options.indexType || options.method) {
options.using = options.indexType || options.method;
}
options.prefix = options.prefix || rawTablename || tableName;
if (options.prefix && _.isString(options.prefix)) {
options.prefix = options.prefix.replace(/\./g, '_');
......@@ -593,7 +566,7 @@ class QueryGenerator {
if (!options.name) {
// Mostly for cases where addIndex is called directly by the user without an options object (for example in migrations)
// All calls that go through sequelize should already have a name
options = this.nameIndexes([options], options.prefix)[0];
options = Utils.nameIndex(options, options.prefix);
}
options = Model._conformIndex(options);
......
......@@ -407,7 +407,7 @@ class MSSQLQueryGenerator extends AbstractQueryGenerator {
}
//Add unique indexes defined by indexes option to uniqueAttrs
for (const index of model.options.indexes) {
for (const index of model._indexes) {
if (index.unique && index.fields) {
for (const field of index.fields) {
const fieldName = typeof field === 'string' ? field : field.name || field.attribute;
......
'use strict';
const DataTypes = require('../../data-types');
const Promise = require('../../promise');
const QueryTypes = require('../../query-types');
const _ = require('lodash');
/**
Returns an object that handles Postgres special needs to do certain queries.
@class QueryInterface
@static
@private
*/
/**
* Ensure enum and their values
*
* @param {String} tableName Name of table to create
* @param {Object} attributes Object representing a list of normalized table attributes
* @param {Object} [attributes]
* @param {Model} [model]
*
* @return {Promise}
* @private
*/
function ensureEnums(tableName, attributes, options, model) {
const keys = Object.keys(attributes);
const keyLen = keys.length;
let sql = '';
let promises = [];
let i = 0;
for (i = 0; i < keyLen; i++) {
const attribute = attributes[keys[i]];
const type = attribute.type;
if (
type instanceof DataTypes.ENUM ||
(type instanceof DataTypes.ARRAY && type.type instanceof DataTypes.ENUM) //ARRAY sub type is ENUM
) {
sql = this.QueryGenerator.pgListEnums(tableName, attribute.field || keys[i], options);
promises.push(this.sequelize.query(
sql,
_.assign({}, options, { plain: true, raw: true, type: QueryTypes.SELECT })
));
}
}
return Promise.all(promises).then(results => {
promises = [];
let enumIdx = 0;
for (i = 0; i < keyLen; i++) {
const attribute = attributes[keys[i]];
const type = attribute.type;
const enumType = type.type || type;
if (
type instanceof DataTypes.ENUM ||
(type instanceof DataTypes.ARRAY && enumType instanceof DataTypes.ENUM) //ARRAY sub type is ENUM
) {
// If the enum type doesn't exist then create it
if (!results[enumIdx]) {
sql = this.QueryGenerator.pgEnum(tableName, attribute.field || keys[i], enumType, options);
promises.push(this.sequelize.query(
sql,
_.assign({}, options, { raw: true })
));
} else if (!!results[enumIdx] && !!model) {
const enumVals = this.QueryGenerator.fromArray(results[enumIdx].enum_value);
const vals = enumType.values;
vals.forEach((value, idx) => {
// reset out after/before options since it's for every enum value
const valueOptions = _.clone(options);
valueOptions.before = null;
valueOptions.after = null;
if (enumVals.indexOf(value) === -1) {
if (vals[idx + 1]) {
valueOptions.before = vals[idx + 1];
}
else if (vals[idx - 1]) {
valueOptions.after = vals[idx - 1];
}
valueOptions.supportsSearchPath = false;
promises.push(this.sequelize.query(this.QueryGenerator.pgEnumAdd(tableName, attribute.field || keys[i], value, valueOptions), valueOptions));
}
});
enumIdx++;
}
}
}
return Promise.all(promises)
.tap(() => {
// If ENUM processed, then refresh OIDs
if (promises.length) {
return this.sequelize.dialect.connectionManager._refreshDynamicOIDs();
}
});
});
}
exports.ensureEnums = ensureEnums;
\ No newline at end of file
'use strict';
const assert = require('assert');
const Dottie = require('dottie');
const _ = require('lodash');
const Utils = require('./utils');
const BelongsTo = require('./associations/belongs-to');
const BelongsToMany = require('./associations/belongs-to-many');
const InstanceValidator = require('./instance-validator');
const QueryTypes = require('./query-types');
const sequelizeErrors = require('./errors');
const Dottie = require('dottie');
const Promise = require('./promise');
const _ = require('lodash');
const Association = require('./associations/base');
const HasMany = require('./associations/has-many');
const DataTypes = require('./data-types');
const Hooks = require('./hooks');
const associationsMixin = require('./associations/mixin');
const defaultsOptions = { raw: true };
const assert = require('assert');
const Op = require('./operators');
/**
......@@ -141,7 +141,7 @@ class Model {
if (Object.keys(defaults).length) {
for (key in defaults) {
if (values[key] === undefined) {
this.set(key, Utils.toDefaultValue(defaults[key], this.sequelize.options.dialect), defaultsOptions);
this.set(key, Utils.toDefaultValue(defaults[key], this.sequelize.options.dialect), { raw: true });
delete values[key];
}
}
......@@ -734,6 +734,24 @@ class Model {
});
}
static _conformIndex(index) {
if (!index.fields) {
throw new Error('Missing "fields" property for index definition');
}
index = _.defaults(index, {
type: '',
parser: null
});
if (index.type && index.type.toLowerCase() === 'unique') {
index.unique = true;
delete index.type;
}
return index;
}
/**
* Initialize a model, representing a table in the DB, with attributes and options.
*
......@@ -772,8 +790,8 @@ class Model {
* @see {@link Hooks}
*
* @param {Object} attributes An object, where each attribute is a column of the table. Each column can be either a DataType, a string or a type-description object, with the properties described below:
* @param {String|DataTypes|Object} attributes.column The description of a database column
* @param {String|DataTypes} attributes.column.type A string or a data type
* @param {String|DataTypes|Object} attributes.column The description of a database column
* @param {String|DataTypes} attributes.column.type A string or a data type
* @param {Boolean} [attributes.column.allowNull=true] If false, the column will have a NOT NULL constraint, and a not null validation will be run before an instance is saved.
* @param {any} [attributes.column.defaultValue=null] A literal default value, a JavaScript function, or an SQL function (see `sequelize.fn`)
* @param {String|Boolean} [attributes.column.unique=false] If true, the column will get a unique constraint. If a string is provided, the column will be part of a composite unique index. If multiple columns have the same string, they will be part of the same unique index
......@@ -805,7 +823,7 @@ class Model {
* @param {Array<Object>} [options.indexes]
* @param {String} [options.indexes[].name] The name of the index. Defaults to model name + _ + fields concatenated
* @param {String} [options.indexes[].type] Index type. Only used by mysql. One of `UNIQUE`, `FULLTEXT` and `SPATIAL`
* @param {String} [options.indexes[].method] The method to create the index by (`USING` statement in SQL). BTREE and HASH are supported by mysql and postgres, and postgres additionally supports GIST and GIN.
* @param {String} [options.indexes[].using] The method to create the index by (`USING` statement in SQL). BTREE and HASH are supported by mysql and postgres, and postgres additionally supports GIST and GIN.
* @param {Boolean} [options.indexes[].unique=false] Should the index by unique? Can also be triggered by setting type to `UNIQUE`
* @param {Boolean} [options.indexes[].concurrently=false] PostgresSQL will build the index without taking any write locks. Postgres only
* @param {Array<String|Object>} [options.indexes[].fields] An array of the fields to index. Each field can either be a string containing the name of the field, a sequelize object (e.g `sequelize.fn`), or an object with the following attributes: `attribute` (field name), `length` (create a prefix index of length chars), `order` (the direction the column should be sorted in), `collate` (the collation (sort order) for the column)
......@@ -919,35 +937,40 @@ class Model {
return attribute;
});
this._indexes = this.options.indexes
.map(index => this._conformIndex(index))
.map(index => Utils.nameIndex(index, this.getTableName()));
this.primaryKeys = {};
this._readOnlyAttributes = [];
this._timestampAttributes = {};
// Setup names of timestamp attributes
// setup names of timestamp attributes
if (this.options.timestamps) {
if (this.options.createdAt !== false) {
this._timestampAttributes.createdAt = this.options.createdAt || 'createdAt';
this._readOnlyAttributes.push(this._timestampAttributes.createdAt);
}
if (this.options.updatedAt !== false) {
this._timestampAttributes.updatedAt = this.options.updatedAt || 'updatedAt';
this._readOnlyAttributes.push(this._timestampAttributes.updatedAt);
}
if (this.options.paranoid && this.options.deletedAt !== false) {
this._timestampAttributes.deletedAt = this.options.deletedAt || 'deletedAt';
this._readOnlyAttributes.push(this._timestampAttributes.deletedAt);
}
}
// Setup name for version attribute
// setup name for version attribute
if (this.options.version) {
this._versionAttribute = typeof this.options.version === 'string' ? this.options.version : 'version';
}
// Add head and tail default attributes (id, timestamps)
this._readOnlyAttributes = _.values(this._timestampAttributes);
if (this._versionAttribute) {
this._readOnlyAttributes.push(this._versionAttribute);
}
this._hasReadOnlyAttributes = this._readOnlyAttributes && this._readOnlyAttributes.length;
this._isReadOnlyAttribute = _.memoize(key => this._hasReadOnlyAttributes && this._readOnlyAttributes.indexOf(key) !== -1);
this._hasReadOnlyAttributes = this._readOnlyAttributes.length > 0;
this._isReadOnlyAttribute = _.memoize(key => this._readOnlyAttributes.includes(key));
// Add head and tail default attributes (id, timestamps)
this._addDefaultAttributes();
this.refreshAttributes();
this._findAutoIncrementAttribute();
......@@ -965,27 +988,12 @@ class Model {
}
});
this.options.indexes = this.options.indexes.map(this._conformIndex);
this.sequelize.modelManager.addModel(this);
this.sequelize.runHooks('afterDefine', this);
return this;
}
static _conformIndex(index) {
index = _.defaults(index, {
type: '',
parser: null
});
if (index.type && index.type.toLowerCase() === 'unique') {
index.unique = true;
delete index.type;
}
return index;
}
static refreshAttributes() {
const attributeManipulation = {};
......@@ -1055,7 +1063,7 @@ class Model {
this.fieldRawAttributesMap = {};
this.primaryKeys = {};
this.options.uniqueKeys = {};
this.uniqueKeys = {};
_.each(this.rawAttributes, (definition, name) => {
definition.type = this.sequelize.normalizeDataType(definition.type);
......@@ -1116,7 +1124,7 @@ class Model {
idxName = this.tableName + '_' + name + '_unique';
}
const idx = this.options.uniqueKeys[idxName] || { fields: [] };
const idx = this.uniqueKeys[idxName] || { fields: [] };
idx.fields.push(definition.field);
idx.msg = idx.msg || definition.unique.msg || null;
......@@ -1124,7 +1132,7 @@ class Model {
idx.column = name;
idx.customIndex = definition.unique !== true;
this.options.uniqueKeys[idxName] = idx;
this.uniqueKeys[idxName] = idx;
}
if (definition.hasOwnProperty('validate')) {
......@@ -1132,10 +1140,15 @@ class Model {
}
if (definition.index === true && definition.type instanceof DataTypes.JSONB) {
this.options.indexes.push({
fields: [definition.field || name],
using: 'gin'
});
this._indexes.push(
Utils.nameIndex(
this._conformIndex({
fields: [definition.field || name],
using: 'gin'
}),
this.getTableName()
)
);
delete definition.index;
}
......@@ -1149,8 +1162,6 @@ class Model {
return map;
}, {});
this.uniqueKeys = this.options.uniqueKeys;
this._hasBooleanAttributes = !!this._booleanAttributes.length;
this._isBooleanAttribute = _.memoize(key => this._booleanAttributes.indexOf(key) !== -1);
......@@ -1289,10 +1300,7 @@ class Model {
})
.then(() => this.QueryInterface.showIndex(this.getTableName(options), options))
.then(indexes => {
// Assign an auto-generated name to indexes which are not named by the user
this.options.indexes = this.QueryInterface.nameIndexes(this.options.indexes, this.tableName);
indexes = _.filter(this.options.indexes, item1 =>
indexes = _.filter(this._indexes, item1 =>
!_.some(indexes, item2 => item1.name === item2.name)
).sort((index1, index2) => {
if (this.sequelize.options.dialect === 'postgres') {
......
......@@ -6,6 +6,7 @@ const DataTypes = require('./data-types');
const SQLiteQueryInterface = require('./dialects/sqlite/query-interface');
const MSSSQLQueryInterface = require('./dialects/mssql/query-interface');
const MySQLQueryInterface = require('./dialects/mysql/query-interface');
const PostgresQueryInterface = require('./dialects/postgres/query-interface');
const Transaction = require('./transaction');
const Promise = require('./promise');
const QueryTypes = require('./query-types');
......@@ -142,7 +143,9 @@ class QueryInterface {
* {
* engine: 'MYISAM', // default: 'InnoDB'
* charset: 'latin1', // default: null
* schema: 'public' // default: public, PostgreSQL only.
* schema: 'public', // default: public, PostgreSQL only.
* comment: 'my table', // comment for table
* collate: 'latin1_danish_ci' // collation, MYSQL only
* }
* )
* ```
......@@ -155,129 +158,41 @@ class QueryInterface {
* @return {Promise}
*/
createTable(tableName, attributes, options, model) {
const keys = Object.keys(attributes);
const keyLen = keys.length;
let sql = '';
let i = 0;
let promise;
options = _.clone(options) || {};
attributes = _.mapValues(attributes, attribute => {
if (!_.isPlainObject(attribute)) {
attribute = { type: attribute, allowNull: true };
}
attribute = this.sequelize.normalizeAttribute(attribute);
if (model) {
options.uniqueKeys = options.uniqueKeys || model.uniqueKeys;
}
return attribute;
});
attributes = _.mapValues(
attributes,
attribute => this.sequelize.normalizeAttribute(attribute)
);
// Postgres requires a special SQL command for enums
// Postgres requires special SQL commands for ENUM/ENUM[]
if (this.sequelize.options.dialect === 'postgres') {
const promises = [];
for (i = 0; i < keyLen; i++) {
const attribute = attributes[keys[i]];
const type = attribute.type;
if (
type instanceof DataTypes.ENUM ||
(type instanceof DataTypes.ARRAY && type.type instanceof DataTypes.ENUM) //ARRAY sub type is ENUM
) {
sql = this.QueryGenerator.pgListEnums(tableName, attribute.field || keys[i], options);
promises.push(this.sequelize.query(
sql,
_.assign({}, options, { plain: true, raw: true, type: QueryTypes.SELECT })
));
}
}
return Promise.all(promises).then(results => {
const promises = [];
let enumIdx = 0;
for (i = 0; i < keyLen; i++) {
const attribute = attributes[keys[i]];
const type = attribute.type;
const enumType = type.type || type;
if (
type instanceof DataTypes.ENUM ||
(type instanceof DataTypes.ARRAY && enumType instanceof DataTypes.ENUM) //ARRAY sub type is ENUM
) {
// If the enum type doesn't exist then create it
if (!results[enumIdx]) {
sql = this.QueryGenerator.pgEnum(tableName, attribute.field || keys[i], enumType, options);
promises.push(this.sequelize.query(
sql,
_.assign({}, options, { raw: true })
));
} else if (!!results[enumIdx] && !!model) {
const enumVals = this.QueryGenerator.fromArray(results[enumIdx].enum_value);
const vals = enumType.values;
vals.forEach((value, idx) => {
// reset out after/before options since it's for every enum value
const valueOptions = _.clone(options);
valueOptions.before = null;
valueOptions.after = null;
if (enumVals.indexOf(value) === -1) {
if (vals[idx + 1]) {
valueOptions.before = vals[idx + 1];
}
else if (vals[idx - 1]) {
valueOptions.after = vals[idx - 1];
}
valueOptions.supportsSearchPath = false;
promises.push(this.sequelize.query(this.QueryGenerator.pgEnumAdd(tableName, attribute.field || keys[i], value, valueOptions), valueOptions));
}
});
enumIdx++;
}
}
}
if (!tableName.schema &&
(options.schema || !!model && model._schema)) {
tableName = this.QueryGenerator.addSchema({
tableName,
_schema: !!model && model._schema || options.schema
});
}
attributes = this.QueryGenerator.attributesToSQL(attributes, {
context: 'createTable'
});
sql = this.QueryGenerator.createTableQuery(tableName, attributes, options);
return Promise.all(promises)
.tap(() => {
// If ENUM processed, then refresh OIDs
if (promises.length) {
return this.sequelize.dialect.connectionManager._refreshDynamicOIDs();
}
})
.then(() => {
return this.sequelize.query(sql, options);
});
});
promise = PostgresQueryInterface.ensureEnums.call(this, tableName, attributes, options, model);
} else {
if (!tableName.schema &&
(options.schema || !!model && model._schema)) {
tableName = this.QueryGenerator.addSchema({
tableName,
_schema: !!model && model._schema || options.schema
});
}
promise = Promise.resolve();
}
attributes = this.QueryGenerator.attributesToSQL(attributes, {
context: 'createTable'
if (
!tableName.schema &&
(options.schema || !!model && model._schema)
) {
tableName = this.QueryGenerator.addSchema({
tableName,
_schema: !!model && model._schema || options.schema
});
sql = this.QueryGenerator.createTableQuery(tableName, attributes, options);
return this.sequelize.query(sql, options);
}
attributes = this.QueryGenerator.attributesToSQL(attributes, { context: 'createTable' });
sql = this.QueryGenerator.createTableQuery(tableName, attributes, options);
return promise.then(() => this.sequelize.query(sql, options));
}
/**
......@@ -684,10 +599,6 @@ class QueryInterface {
return this.sequelize.query(sql, _.assign({}, options, { type: QueryTypes.SHOWINDEXES }));
}
nameIndexes(indexes, rawTablename) {
return this.QueryGenerator.nameIndexes(indexes, rawTablename);
}
getForeignKeysForTables(tableNames, options) {
if (tableNames.length === 0) {
return Promise.resolve({});
......@@ -933,12 +844,12 @@ class QueryInterface {
wheres.push(where);
}
// Lets combine uniquekeys and indexes into one
indexes = _.map(model.options.uniqueKeys, value => {
// Lets combine unique keys and indexes into one
indexes = _.map(model.uniqueKeys, value => {
return value.fields;
});
_.each(model.options.indexes, value => {
_.each(model._indexes, value => {
if (value.unique) {
// fields in the index may both the strings or objects with an attribute property - lets sanitize that
indexFields = _.map(value.fields, field => {
......
......@@ -648,3 +648,28 @@ function classToInvokable(Class) {
}
exports.classToInvokable = classToInvokable;
/**
*
* @param {Object} index
* @param {Array} index.fields
* @param {String} [index.name]
* @param {String|Object} tableName
*
* @returns {Object}
* @private
*/
function nameIndex(index, tableName) {
if (tableName.tableName) tableName = tableName.tableName;
if (!index.hasOwnProperty('name')) {
const fields = index.fields.map(
field => typeof field === 'string' ? field : field.name || field.attribute
);
index.name = underscore(tableName + '_' + fields.join('_'));
}
return index;
}
exports.nameIndex = nameIndex;
......@@ -1570,8 +1570,8 @@ describe(Support.getTestDialectTeaser('BelongsToMany'), () => {
expect(Object.keys(this.UserTasks2.primaryKeys)).to.deep.equal(['userTasksId']);
_.each([this.UserTasks, this.UserTasks2], model => {
fk = Object.keys(model.options.uniqueKeys)[0];
expect(model.options.uniqueKeys[fk].fields.sort()).to.deep.equal(['TaskId', 'UserId']);
fk = Object.keys(model.uniqueKeys)[0];
expect(model.uniqueKeys[fk].fields.sort()).to.deep.equal(['TaskId', 'UserId']);
});
});
......
......@@ -265,74 +265,6 @@ describe(Support.getTestDialectTeaser('QueryInterface'), () => {
});
});
// FIXME: These tests should make assertions against the created table using describeTable
describe('createTable', () => {
it('should create a auto increment primary key', function() {
return this.queryInterface.createTable('TableWithPK', {
table_id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
}
}).bind(this).then(function() {
return this.queryInterface.insert(null, 'TableWithPK', {}, {raw: true, returning: true, plain: true}).then(results => {
const response = _.head(results);
expect(response.table_id || typeof response !== 'object' && response).to.be.ok;
});
});
});
it('should work with enums (1)', function() {
return this.queryInterface.createTable('SomeTable', {
someEnum: DataTypes.ENUM('value1', 'value2', 'value3')
});
});
it('should work with enums (2)', function() {
return this.queryInterface.createTable('SomeTable', {
someEnum: {
type: DataTypes.ENUM,
values: ['value1', 'value2', 'value3']
}
});
});
it('should work with enums (3)', function() {
return this.queryInterface.createTable('SomeTable', {
someEnum: {
type: DataTypes.ENUM,
values: ['value1', 'value2', 'value3'],
field: 'otherName'
}
});
});
it('should work with enums (4)', function() {
return this.queryInterface.createSchema('archive').bind(this).then(function() {
return this.queryInterface.createTable('SomeTable', {
someEnum: {
type: DataTypes.ENUM,
values: ['value1', 'value2', 'value3'],
field: 'otherName'
}
}, { schema: 'archive' });
});
});
it('should work with schemas', function() {
const self = this;
return self.sequelize.createSchema('hero').then(() => {
return self.queryInterface.createTable('User', {
name: {
type: DataTypes.STRING
}
}, {
schema: 'hero'
});
});
});
});
describe('renameColumn', () => {
it('rename a simple column', function() {
const self = this;
......
'use strict';
const chai = require('chai');
const expect = chai.expect;
const Support = require(__dirname + '/../support');
const DataTypes = require(__dirname + '/../../../lib/data-types');
const _ = require('lodash');
describe(Support.getTestDialectTeaser('QueryInterface'), () => {
beforeEach(function () {
this.sequelize.options.quoteIdenifiers = true;
this.queryInterface = this.sequelize.getQueryInterface();
});
afterEach(function () {
return this.sequelize.dropAllSchemas();
});
// FIXME: These tests should make assertions against the created table using describeTable
describe('createTable', () => {
it('should create a auto increment primary key', function () {
return this.queryInterface.createTable('TableWithPK', {
table_id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
}
}).then(() => {
return this.queryInterface.insert(null, 'TableWithPK', {}, { raw: true, returning: true, plain: true })
.then(results => {
const response = _.head(results);
expect(response.table_id || typeof response !== 'object' && response).to.be.ok;
});
});
});
it('should work with enums (1)', function () {
return this.queryInterface.createTable('SomeTable', {
someEnum: DataTypes.ENUM('value1', 'value2', 'value3')
});
});
it('should work with enums (2)', function () {
return this.queryInterface.createTable('SomeTable', {
someEnum: {
type: DataTypes.ENUM,
values: ['value1', 'value2', 'value3']
}
});
});
it('should work with enums (3)', function () {
return this.queryInterface.createTable('SomeTable', {
someEnum: {
type: DataTypes.ENUM,
values: ['value1', 'value2', 'value3'],
field: 'otherName'
}
});
});
it('should work with enums (4)', function () {
return this.queryInterface.createSchema('archive').bind(this).then(function () {
return this.queryInterface.createTable('SomeTable', {
someEnum: {
type: DataTypes.ENUM,
values: ['value1', 'value2', 'value3'],
field: 'otherName'
}
}, { schema: 'archive' });
});
});
it('should work with schemas', function () {
const self = this;
return self.sequelize.createSchema('hero').then(() => {
return self.queryInterface.createTable('User', {
name: {
type: DataTypes.STRING
}
}, {
schema: 'hero'
});
});
});
});
});
\ No newline at end of file
......@@ -18,25 +18,27 @@ describe(Support.getTestDialectTeaser('Model'), () => {
});
expect(Model.rawAttributes.eventData.index).not.to.equal(true);
expect(Model.options.indexes.length).to.equal(1);
expect(Model.options.indexes[0].fields).to.eql(['data']);
expect(Model.options.indexes[0].using).to.equal('gin');
expect(Model._indexes.length).to.equal(1);
expect(Model._indexes[0].fields).to.eql(['data']);
expect(Model._indexes[0].using).to.equal('gin');
});
it('should set the unique property when type is unique', () => {
const Model = current.define('m', {}, {
indexes: [
{
type: 'unique'
type: 'unique',
fields: ['name']
},
{
type: 'UNIQUE'
type: 'UNIQUE',
fields: ['name']
}
]
});
expect(Model.options.indexes[0].unique).to.eql(true);
expect(Model.options.indexes[1].unique).to.eql(true);
expect(Model._indexes[0].unique).to.eql(true);
expect(Model._indexes[1].unique).to.eql(true);
});
it('should not set rawAttributes when indexes are defined via options', () => {
......
......@@ -37,7 +37,7 @@ suite(Support.getTestDialectTeaser('SQL'), () => {
}
});
test('type and method', () => {
test('type and using', () => {
expectsql(sql.addIndexQuery('User', ['fieldC'], {
type: 'FULLTEXT',
concurrently: true
......@@ -51,7 +51,7 @@ suite(Support.getTestDialectTeaser('SQL'), () => {
expectsql(sql.addIndexQuery('User', ['fieldB', {attribute: 'fieldA', collate: 'en_US', order: 'DESC', length: 5}], {
name: 'a_b_uniq',
unique: true,
method: 'BTREE',
using: 'BTREE',
parser: 'foo'
}), {
sqlite: 'CREATE UNIQUE INDEX `a_b_uniq` ON `User` (`fieldB`, `fieldA` COLLATE `en_US` DESC)',
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!