Skip to content

Commit

Permalink
Remove auxiliar methods from Model prototype
Browse files Browse the repository at this point in the history
  • Loading branch information
Ricardo Gama committed Oct 6, 2016
1 parent e2dc321 commit 3131e99
Showing 1 changed file with 70 additions and 47 deletions.
117 changes: 70 additions & 47 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,76 @@ import { flattenDeep, reduce } from 'lodash';

export default Bookshelf => {
const Model = Bookshelf.Model.prototype;
const client = Bookshelf.knex.client.config.client;
const knex = Bookshelf.knex;
const client = knex.client.config.client;
const quoteColumns = client === 'postgres' || client === 'postgresql' || client === 'pg';

/**
* Dependency map.
*/

function dependencyMap(skipDependents = false) {
if (skipDependents || !this.dependents) {
return;
}

return reduce(this.dependents, (result, dependent) => {
const { relatedData } = this.prototype[dependent]();
const skipDependents = relatedData.type === 'belongsToMany';

return [
...result, {
dependents: dependencyMap.call(relatedData.target, skipDependents),
key: relatedData.key('foreignKey'),
model: relatedData.target,
skipDependents,
tableName: skipDependents ? relatedData.joinTable() : relatedData.target.prototype.tableName
}
];
}, []);
}

/**
* Recursive deletes.
*/

function recursiveDeletes(parent) {
// Stringify in case of parent being an instance of query.
const parentValue = typeof parent === 'number' || typeof parent === 'string' ? `'${parent}'` : parent.toString();
const dependencies = dependencyMap.call(this);

// Build delete queries for each dependent.
return reduce(dependencies, (result, { tableName, key, model, skipDependents }) => {
const whereClause = `${quoteColumns ? `"${key}"` : key} IN (${parentValue})`;

return [
...result,
transaction => transaction(tableName).del().whereRaw(whereClause),
skipDependents ? [] : recursiveDeletes.call(model, knex(tableName).column(model.prototype.idAttribute).whereRaw(whereClause))
];
}, []);
}

/**
* Cascade delete.
*/

function cascadeDelete(transacting, options) {
const id = this.get(this.idAttribute) || this._knex.column(this.idAttribute);
const queries = recursiveDeletes.call(this.constructor, id);

return mapSeries(flattenDeep(queries).reverse(), query => query(transacting))
.then(() => Model.destroy.call(this, {
...options,
transacting
}));
}

/**
* Extend Model `destroy` method.
*/

Bookshelf.Model = Bookshelf.Model.extend({
cascadeDelete(transaction, options) {
const queries = this.constructor.recursiveDeletes(this.get(this.idAttribute) || this._knex.column(this.idAttribute), options);

return mapSeries(flattenDeep(queries).reverse(), query => query(transaction))
.then(() => Model.destroy.call(this, {
...options,
transacting: transaction
}));
},
destroy(options) {
options = options || {};

Expand All @@ -32,45 +90,10 @@ export default Bookshelf => {
}

if (options.transacting) {
return this.cascadeDelete(options.transacting, options);
}

return Bookshelf.knex.transaction(transaction => this.cascadeDelete(transaction, options));
}
}, {
dependencyMap(skipDependents = false) {
if (skipDependents || !this.dependents) {
return;
return cascadeDelete.call(this, options.transacting, options);
}

return reduce(this.dependents, (result, dependent) => {
const { relatedData } = this.prototype[dependent]();
const skipDependents = relatedData.type === 'belongsToMany';

return [
...result, {
dependents: relatedData.target.dependencyMap(skipDependents),
key: relatedData.key('foreignKey'),
model: relatedData.target,
skipDependents,
tableName: skipDependents ? relatedData.joinTable() : relatedData.target.prototype.tableName
}];
}, []);
},
recursiveDeletes(parent) {
// Stringify in case of parent being an instance of query.
const parentValue = typeof parent === 'number' || typeof parent === 'string' ? `'${parent}'` : parent.toString();

// Build delete queries for each dependent.
return reduce(this.dependencyMap(), (result, { tableName, key, model, skipDependents }) => {
const whereClause = `${client === 'postgres' ? `"${key}"` : key} IN (${parentValue})`;

return [
...result,
transaction => transaction(tableName).del().whereRaw(whereClause),
skipDependents ? [] : model.recursiveDeletes(Bookshelf.knex(tableName).column(model.prototype.idAttribute).whereRaw(whereClause))
];
}, []);
return Bookshelf.knex.transaction(transacting => cascadeDelete.call(this, transacting, options));
}
});
};

0 comments on commit 3131e99

Please sign in to comment.