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

Commit 1eeb343a by Sushant Committed by GitHub

feat(internal): cleanup code base and straightening internal API (#8160)

* autoIncrementField => autoIncrementAttribute

* fieldMap

* this.hasPrimaryKey duplicate removed

* use this.rawAttributes

* remove unused model/attribute file

* dynamically load errors

* parse and properly throw UnknownConstraintError for postgres
1 parent fc2e42ca
......@@ -198,13 +198,13 @@ class AbstractQuery {
handleInsertQuery(results, metaData) {
if (this.instance) {
// add the inserted row id to the instance
const autoIncrementField = this.model.autoIncrementField;
const autoIncrementAttribute = this.model.autoIncrementAttribute;
let id = null;
id = id || results && results[this.getInsertIdField()];
id = id || metaData && metaData[this.getInsertIdField()];
this.instance[autoIncrementField] = id;
this.instance[autoIncrementAttribute] = id;
}
}
......
......@@ -613,21 +613,6 @@ const QueryGenerator = {
return result;
},
findAutoIncrementField(factory) {
const fields = [];
for (const name in factory.attributes) {
if (factory.attributes.hasOwnProperty(name)) {
const definition = factory.attributes[name];
if (definition && definition.autoIncrement) {
fields.push(name);
}
}
}
return fields;
},
createTrigger() {
throwMethodUndefined('createTrigger');
},
......
......@@ -374,20 +374,20 @@ class Query extends AbstractQuery {
handleInsertQuery(results, metaData) {
if (this.instance) {
// add the inserted row id to the instance
const autoIncrementField = this.model.autoIncrementField;
const autoIncrementAttribute = this.model.autoIncrementAttribute;
let id = null;
let autoIncrementFieldAlias = null;
let autoIncrementAttributeAlias = null;
if (this.model.rawAttributes.hasOwnProperty(autoIncrementField) &&
this.model.rawAttributes[autoIncrementField].field !== undefined)
autoIncrementFieldAlias = this.model.rawAttributes[autoIncrementField].field;
if (this.model.rawAttributes.hasOwnProperty(autoIncrementAttribute) &&
this.model.rawAttributes[autoIncrementAttribute].field !== undefined)
autoIncrementAttributeAlias = this.model.rawAttributes[autoIncrementAttribute].field;
id = id || results && results[0][this.getInsertIdField()];
id = id || metaData && metaData[this.getInsertIdField()];
id = id || results && results[0][autoIncrementField];
id = id || autoIncrementFieldAlias && results && results[0][autoIncrementFieldAlias];
id = id || results && results[0][autoIncrementAttribute];
id = id || autoIncrementAttributeAlias && results && results[0][autoIncrementAttributeAlias];
this.instance[autoIncrementField] = id;
this.instance[autoIncrementAttribute] = id;
}
}
}
......
......@@ -295,22 +295,6 @@ const QueryGenerator = {
return result;
},
findAutoIncrementField(factory) {
const fields = [];
for (const name in factory.attributes) {
if (factory.attributes.hasOwnProperty(name)) {
const definition = factory.attributes[name];
if (definition && definition.autoIncrement) {
fields.push(name);
}
}
}
return fields;
},
quoteIdentifier(identifier) {
if (identifier === '*') return identifier;
return Utils.addTicks(Utils.removeTicks(identifier, '`'), '`');
......
......@@ -97,8 +97,8 @@ class Query extends AbstractQuery {
if (
data.constructor.name === 'ResultSetHeader'
&& this.model
&& this.model.autoIncrementField
&& this.model.autoIncrementField === this.model.primaryKeyAttribute
&& this.model.autoIncrementAttribute
&& this.model.autoIncrementAttribute === this.model.primaryKeyAttribute
&& this.model.rawAttributes[this.model.primaryKeyAttribute]
) {
const startId = data[this.getInsertIdField()];
......
......@@ -587,20 +587,6 @@ const QueryGenerator = {
return result;
},
findAutoIncrementField(factory) {
const fields = [];
for (const name in factory.attributes) {
const definition = factory.attributes[name];
if (definition && definition.autoIncrement) {
fields.push(name);
}
}
return fields;
},
createTrigger(tableName, triggerName, eventType, fireOnSpec, functionName, functionParams, optionsArray) {
const decodedEventType = this.decodeTriggerEventType(eventType);
......
......@@ -179,7 +179,7 @@ class Query extends AbstractQuery {
// Postgres will treat tables as case-insensitive, so fix the case
// of the returned values to match attributes
if (this.options.raw === false && this.sequelize.options.quoteIdentifiers === false) {
const attrsMap = _.reduce(this.model.attributes, (m, v, k) => {
const attrsMap = _.reduce(this.model.rawAttributes, (m, v, k) => {
m[k.toLowerCase()] = k;
return m;
}, {});
......@@ -334,6 +334,19 @@ class Query extends AbstractQuery {
parent: err
});
case '42704':
if (err.sql && /CONSTRAINT/gi.test(err.sql)) {
message = 'Unknown constraint error';
throw new sequelizeErrors.UnknownConstraintError({
message,
constraint: err.constraint,
fields,
table: err.table,
parent: err
});
}
default:
return new sequelizeErrors.DatabaseError(err);
}
......
......@@ -318,21 +318,6 @@ const QueryGenerator = {
return result;
},
findAutoIncrementField(factory) {
const fields = [];
for (const name in factory.attributes) {
if (factory.attributes.hasOwnProperty(name)) {
const definition = factory.attributes[name];
if (definition && definition.autoIncrement) {
fields.push(name);
}
}
}
return fields;
},
showIndexesQuery(tableName) {
return `PRAGMA INDEX_LIST(${this.quoteTable(tableName)})`;
},
......
......@@ -129,8 +129,8 @@ class Query extends AbstractQuery {
if (
metaData.constructor.name === 'Statement'
&& query.model
&& query.model.autoIncrementField
&& query.model.autoIncrementField === query.model.primaryKeyAttribute
&& query.model.autoIncrementAttribute
&& query.model.autoIncrementAttribute === query.model.primaryKeyAttribute
&& query.model.rawAttributes[query.model.primaryKeyAttribute]
) {
const startId = metaData[query.getInsertIdField()] - metaData.changes + 1;
......
......@@ -22,7 +22,7 @@ class InstanceValidator {
options = _.clone(options) || {};
if (options.fields && !options.skip) {
options.skip = Utils._.difference(Object.keys(modelInstance.constructor.attributes), options.fields);
options.skip = Utils._.difference(Object.keys(modelInstance.constructor.rawAttributes), options.fields);
}
// assign defined and default options
......
......@@ -38,7 +38,6 @@ const assert = require('assert');
* @mixes Hooks
*/
class Model {
static get QueryInterface() {
return this.sequelize.getQueryInterface();
}
......@@ -121,6 +120,7 @@ class Model {
_autoGenerated: true
};
}
if (this._timestampAttributes.updatedAt) {
tail[this._timestampAttributes.updatedAt] = {
type: DataTypes.DATE,
......@@ -128,12 +128,14 @@ class Model {
_autoGenerated: true
};
}
if (this._timestampAttributes.deletedAt) {
tail[this._timestampAttributes.deletedAt] = {
type: DataTypes.DATE,
_autoGenerated: true
};
}
if (this._versionAttribute) {
tail[this._versionAttribute] = {
type: DataTypes.INTEGER,
......@@ -165,16 +167,19 @@ class Model {
}
}
static _findAutoIncrementField() {
const fields = this.QueryGenerator.findAutoIncrementField(this);
this.autoIncrementField = null;
static _findAutoIncrementAttribute() {
this.autoIncrementAttribute = null;
for (const field of fields) {
if (this.autoIncrementField) {
throw new Error('Invalid Instance definition. Only one autoincrement field allowed.');
} else {
this.autoIncrementField = field;
for (const name in this.rawAttributes) {
if (this.rawAttributes.hasOwnProperty(name)) {
const definition = this.rawAttributes[name];
if (definition && definition.autoIncrement) {
if (this.autoIncrementAttribute) {
throw new Error('Invalid Instance definition. Only one autoincrement field allowed.');
} else {
this.autoIncrementAttribute = name;
}
}
}
}
}
......@@ -705,6 +710,7 @@ class Model {
if (!options.sequelize) {
throw new Error('No Sequelize instance passed');
}
this.sequelize = options.sequelize;
const globalOptions = this.sequelize.options;
......@@ -782,18 +788,18 @@ class Model {
}
});
this.attributes = this.rawAttributes = _.mapValues(attributes, (attribute, name) => {
this.rawAttributes = _.mapValues(attributes, (attribute, name) => {
attribute = this.sequelize.normalizeAttribute(attribute);
if (attribute.references && attribute.references.model && attribute.references.model.prototype instanceof Model) {
attribute.references.model = attribute.references.model.tableName;
}
if (attribute.type === undefined) {
throw new Error('Unrecognized data type for field ' + name);
}
if (_.get(attribute, 'references.model.prototype') instanceof Model) {
attribute.references.model = attribute.references.model.tableName;
}
return attribute;
});
......@@ -813,11 +819,7 @@ class Model {
}
}
if (this.options.version) {
if (typeof this.options.version === 'string') {
this._versionAttribute = this.options.version;
} else {
this._versionAttribute = 'version';
}
this._versionAttribute = typeof this.options.version === 'string' ? this.options.version : 'version';
}
// Add head and tail default attributes (id, timestamps)
......@@ -827,10 +829,10 @@ class Model {
}
this._hasReadOnlyAttributes = this._readOnlyAttributes && this._readOnlyAttributes.length;
this._isReadOnlyAttribute = Utils._.memoize(key => this._hasReadOnlyAttributes && this._readOnlyAttributes.indexOf(key) !== -1);
this._addDefaultAttributes();
this.refreshAttributes();
this._findAutoIncrementField();
this._findAutoIncrementAttribute();
this._scope = this.options.defaultScope;
......@@ -845,9 +847,8 @@ class Model {
});
this.options.indexes = this.options.indexes.map(this._conformIndex);
this.sequelize.modelManager.addModel(this);
this.sequelize.runHooks('afterDefine', this);
return this;
......@@ -1037,7 +1038,10 @@ class Model {
this._hasDefaultValues = !Utils._.isEmpty(this._defaultValues);
// DEPRECATE: All code base is free from this.attributes now
// This should be removed in v5
this.attributes = this.rawAttributes;
this.tableAttributes = Utils._.omit(this.rawAttributes, this._virtualAttributes);
this.prototype._hasCustomGetters = Object.keys(this.prototype._customGetters).length;
......@@ -1063,11 +1067,8 @@ class Model {
this.primaryKeyField = this.rawAttributes[this.primaryKeyAttribute].field || this.primaryKeyAttribute;
}
this.primaryKeyCount = this.primaryKeyAttributes.length;
this._hasPrimaryKeys = this.options.hasPrimaryKeys = this.hasPrimaryKeys = this.primaryKeyCount > 0;
this._hasPrimaryKeys = this.primaryKeyAttributes.length > 0;
this._isPrimaryKey = Utils._.memoize(key => this.primaryKeyAttributes.indexOf(key) !== -1);
}
/**
......@@ -2632,7 +2633,7 @@ class Model {
}
// We want to skip validations for all other fields
options.skip = Utils._.difference(Object.keys(this.attributes), Object.keys(values));
options.skip = Utils._.difference(Object.keys(this.rawAttributes), Object.keys(values));
return build.validate(options).then(attributes => {
options.skip = undefined;
if (attributes && attributes.dataValues) {
......@@ -2958,7 +2959,6 @@ class Model {
this._changed = {};
this._modelOptions = this.constructor.options;
this._options = options || {};
this.hasPrimaryKeys = this.constructor.options.hasPrimaryKeys;
this.__eagerlyLoadedAssociations = [];
/**
* Returns true if this instance has not yet been persisted to the database
......@@ -3432,9 +3432,9 @@ class Model {
if (!options.fields) {
if (this.isNewRecord) {
options.fields = Object.keys(this.constructor.attributes);
options.fields = Object.keys(this.constructor.rawAttributes);
} else {
options.fields = _.intersection(this.changed(), Object.keys(this.constructor.attributes));
options.fields = _.intersection(this.changed(), Object.keys(this.constructor.rawAttributes));
}
options.defaultFields = options.fields;
......
'use strict';
class Attribute {
constructor(options) {
if (options.type === undefined) options = {type: options};
this.type = options.type;
}
}
module.exports = Attribute;
module.exports.Attribute = Attribute;
module.exports.default = Attribute;
......@@ -437,9 +437,9 @@ class Sequelize {
options.model = options.instance.constructor;
}
// Map raw fields to model field names using the `fieldAttributeMap`
if (options.model && options.mapToModel && !Utils._.isEmpty(options.model.fieldAttributeMap)) {
options.fieldMap = options.model.fieldAttributeMap;
// map raw fields to model attributes
if (options.mapToModel) {
options.fieldMap = _.get(options, 'model.fieldAttributeMap', {});
}
if (typeof sql === 'object') {
......@@ -1196,59 +1196,16 @@ Sequelize.useInflection = Utils.useInflection;
Hooks.applyTo(Sequelize);
Hooks.applyTo(Sequelize.prototype);
Sequelize.prototype.Error = Sequelize.Error =
sequelizeErrors.BaseError;
Sequelize.prototype.ValidationError = Sequelize.ValidationError =
sequelizeErrors.ValidationError;
Sequelize.prototype.ValidationErrorItem = Sequelize.ValidationErrorItem =
sequelizeErrors.ValidationErrorItem;
Sequelize.prototype.OptimisticLockError = Sequelize.OptimisticLockError =
sequelizeErrors.OptimisticLockError;
Sequelize.prototype.DatabaseError = Sequelize.DatabaseError =
sequelizeErrors.DatabaseError;
Sequelize.prototype.TimeoutError = Sequelize.TimeoutError =
sequelizeErrors.TimeoutError;
Sequelize.prototype.UniqueConstraintError = Sequelize.UniqueConstraintError =
sequelizeErrors.UniqueConstraintError;
Sequelize.prototype.ExclusionConstraintError = Sequelize.ExclusionConstraintError =
sequelizeErrors.ExclusionConstraintError;
Sequelize.prototype.ForeignKeyConstraintError = Sequelize.ForeignKeyConstraintError =
sequelizeErrors.ForeignKeyConstraintError;
Sequelize.prototype.ConnectionError = Sequelize.ConnectionError =
sequelizeErrors.ConnectionError;
Sequelize.prototype.ConnectionRefusedError = Sequelize.ConnectionRefusedError =
sequelizeErrors.ConnectionRefusedError;
Sequelize.prototype.AccessDeniedError = Sequelize.AccessDeniedError =
sequelizeErrors.AccessDeniedError;
Sequelize.prototype.HostNotFoundError = Sequelize.HostNotFoundError =
sequelizeErrors.HostNotFoundError;
Sequelize.prototype.HostNotReachableError = Sequelize.HostNotReachableError =
sequelizeErrors.HostNotReachableError;
Sequelize.prototype.InvalidConnectionError = Sequelize.InvalidConnectionError =
sequelizeErrors.InvalidConnectionError;
Sequelize.prototype.ConnectionTimedOutError = Sequelize.ConnectionTimedOutError =
sequelizeErrors.ConnectionTimedOutError;
Sequelize.prototype.InstanceError = Sequelize.InstanceError =
sequelizeErrors.InstanceError;
Sequelize.prototype.EmptyResultError = Sequelize.EmptyResultError =
sequelizeErrors.EmptyResultError;
/**
* Expose various errors available
*/
for (const error of Object.keys(sequelizeErrors)) {
if (sequelizeErrors[error] === sequelizeErrors.BaseError) {
Sequelize.prototype.Error = Sequelize.Error = sequelizeErrors.BaseError;
} else {
Sequelize.prototype[error] = Sequelize[error] = sequelizeErrors[error];
}
}
module.exports = Sequelize;
module.exports.Sequelize = Sequelize;
......
......@@ -29,25 +29,25 @@ describe(Support.getTestDialectTeaser('associations'), () => {
const reqValidForeignKey = { foreignKey: { allowNull: false }};
this.A.belongsTo(this.B, reqValidForeignKey);
this.A.belongsTo(this.C, reqValidForeignKey);
expect(this.A.attributes.CId.type).to.deep.equal(this.C.attributes.id.type);
expect(this.A.rawAttributes.CId.type).to.deep.equal(this.C.rawAttributes.id.type);
});
it('should not be overwritten for belongsToMany', function() {
const reqValidForeignKey = { foreignKey: { allowNull: false }, through: 'ABBridge'};
this.B.belongsToMany(this.A, reqValidForeignKey);
this.A.belongsTo(this.C, reqValidForeignKey);
expect(this.A.attributes.CId.type).to.deep.equal(this.C.attributes.id.type);
expect(this.A.rawAttributes.CId.type).to.deep.equal(this.C.rawAttributes.id.type);
});
it('should not be overwritten for hasOne', function() {
const reqValidForeignKey = { foreignKey: { allowNull: false }};
this.B.hasOne(this.A, reqValidForeignKey);
this.A.belongsTo(this.C, reqValidForeignKey);
expect(this.A.attributes.CId.type).to.deep.equal(this.C.attributes.id.type);
expect(this.A.rawAttributes.CId.type).to.deep.equal(this.C.rawAttributes.id.type);
});
it('should not be overwritten for hasMany', function() {
const reqValidForeignKey = { foreignKey: { allowNull: false }};
this.B.hasMany(this.A, reqValidForeignKey);
this.A.belongsTo(this.C, reqValidForeignKey);
expect(this.A.attributes.CId.type).to.deep.equal(this.C.attributes.id.type);
expect(this.A.rawAttributes.CId.type).to.deep.equal(this.C.rawAttributes.id.type);
});
});
});
......@@ -12,10 +12,10 @@ describe(Support.getTestDialectTeaser('hasOne'), () => {
Task = current.define('Task', { title: DataTypes.STRING });
User.hasOne(Task);
expect(Task.attributes.UserId).not.to.be.empty;
expect(Task.rawAttributes.UserId).not.to.be.empty;
User.hasOne(Task, {as : 'Shabda'});
expect(Task.attributes.ShabdaId).not.to.be.empty;
expect(Task.rawAttributes.ShabdaId).not.to.be.empty;
});
it('should not override custom methods with association mixin', () => {
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!