mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-30 06:12:03 +03:00
fa4e2cf286
no issue
296 lines
12 KiB
JavaScript
296 lines
12 KiB
JavaScript
'use strict';
|
|
|
|
const mockKnex = require('mock-knex'),
|
|
_ = require('lodash'),
|
|
debug = require('ghost-ignition').debug('tests:knex-mock'),
|
|
DataGenerator = require('../fixtures/data-generator'),
|
|
knex = require('../../../server/data/db').knex;
|
|
|
|
/**
|
|
* Knex mock. The database is our Datagenerator.
|
|
* You can either self register queries or you simply rely on the data generator data.
|
|
*
|
|
* Please extend if you use-case does not work.
|
|
*
|
|
* @TODO: sqlite3 :memory: mode wasn't working for me
|
|
*/
|
|
class KnexMock {
|
|
initialiseDb() {
|
|
this.db = {};
|
|
|
|
_.each(_.pick(_.cloneDeep(DataGenerator.forKnex), [
|
|
'posts',
|
|
'users',
|
|
'tags',
|
|
'permissions',
|
|
'roles',
|
|
'posts_authors',
|
|
'posts_tags'
|
|
]), (objects, tableName) => {
|
|
this.db[tableName] = [];
|
|
|
|
_.each(objects, (object) => {
|
|
this.db[tableName].push(object);
|
|
});
|
|
});
|
|
}
|
|
|
|
resetDb() {
|
|
return this.initialiseDb();
|
|
}
|
|
|
|
mock(options) {
|
|
options = options || {autoMock: true};
|
|
mockKnex.mock(knex);
|
|
|
|
this.initialiseDb();
|
|
|
|
this.tracker = mockKnex.getTracker();
|
|
this.tracker.install();
|
|
|
|
if (options.autoMock) {
|
|
this.tracker.on('query', (query) => {
|
|
query.sql = query.sql.replace(/`/g, '"');
|
|
debug('#### Query start.');
|
|
debug(query.sql);
|
|
|
|
// CASE: transactions
|
|
if (query.sql.match(/BEGIN|COMMIT|ROLLBACK/)) {
|
|
query.response();
|
|
debug('#### Query end.\n');
|
|
return;
|
|
}
|
|
|
|
if (query.method === 'select') {
|
|
if (query.bindings.length && query.sql.match(/where/)) {
|
|
// CASE: joins should return e.g. `posts_tags=[tag,tag]`
|
|
if (query.sql.match(/inner\sjoin/)) {
|
|
let targetTable = query.sql.match(/inner\sjoin\s(\"\w+\")/)[1],
|
|
targetAttribute = query.sql.match(/on\s\"\w+\"\.(\"\w+\")/)[1],
|
|
joinAttribute = query.sql.match(/on\s\"\w+\"\.\"\w+\"\s\=\s\"\w+\"\.(\"\w+\")/)[1],
|
|
joinTable = query.sql.match(/on\s\"\w+\"\.\"\w+\"\s\=\s(\"\w+\")/)[1],
|
|
targetIdentifier = query.sql.match(/(\"\w+\")\sin\s\(\?\)/),
|
|
value = query.bindings[0],
|
|
targetEntries,
|
|
toReturn = [];
|
|
|
|
if (targetIdentifier) {
|
|
targetIdentifier = targetIdentifier[1];
|
|
} else {
|
|
targetIdentifier = query.sql.match(/where\s\"\w+\"\.\"(\w+)\"\s\=/)[1];
|
|
}
|
|
|
|
targetTable = targetTable.replace(/"/g, '');
|
|
targetIdentifier = targetIdentifier.replace(/"/g, '');
|
|
targetAttribute = targetAttribute.replace(/"/g, '');
|
|
joinTable = joinTable.replace(/"/g, '');
|
|
joinAttribute = joinAttribute.replace(/"/g, '');
|
|
|
|
debug(targetTable, targetIdentifier, targetAttribute, joinTable, joinAttribute);
|
|
|
|
targetEntries = _.filter(this.db[targetTable], ((existing) => {
|
|
if (existing[targetIdentifier] === value) {
|
|
return true;
|
|
}
|
|
}));
|
|
|
|
if (targetEntries && targetEntries.length) {
|
|
_.each(targetEntries, ((target) => {
|
|
const found = _.find(this.db[joinTable], ((joinEntry) => {
|
|
if (joinEntry[joinAttribute] === target[targetAttribute]) {
|
|
return true;
|
|
}
|
|
}));
|
|
|
|
_.each(target, function (value, key) {
|
|
let match = query.sql.match(new RegExp('\\"' + targetTable + '\\"\\.\\"' + key + '"\\sas\\s(\\"\\w+\\")'));
|
|
|
|
// CASE: e.g. id
|
|
if (match) {
|
|
match = match[1];
|
|
match = match.replace(/"/g, '');
|
|
found[match] = value;
|
|
}
|
|
});
|
|
|
|
if (found) {
|
|
toReturn.push(found);
|
|
}
|
|
}));
|
|
|
|
// @TODO: This is not really generic ;)
|
|
toReturn = _.orderBy(toReturn, ['_pivot_sort_order'], ['asc']);
|
|
query.response(toReturn);
|
|
debug('#### Query end.\n');
|
|
} else {
|
|
query.response([]);
|
|
debug('#### Query end.\n');
|
|
}
|
|
} else {
|
|
let tableName = query.sql.match(/from\s\"(\w+)\"/)[1],
|
|
where = query.sql.match(/\"(\w+)\"\s\=\s\?/),
|
|
value = query.bindings[0],
|
|
dbEntry;
|
|
|
|
// where "users"."id" in ('1')
|
|
if (!where) {
|
|
where = query.sql.match(/\"\w+\"\.\"(\w+)\"\sin\s\(\?\)/)[1];
|
|
} else {
|
|
where = where[1];
|
|
}
|
|
|
|
debug(tableName, where, value);
|
|
|
|
dbEntry = _.filter(this.db[tableName], ((existing) => {
|
|
if (existing[where] === value) {
|
|
return true;
|
|
}
|
|
}));
|
|
|
|
if (dbEntry) {
|
|
// select fields
|
|
dbEntry = _.map(dbEntry, (obj) => {
|
|
let keys = query.sql.match(/select\s(\".*\"\,?)+\sfrom/);
|
|
|
|
if (keys) {
|
|
keys = keys[1];
|
|
keys = keys.replace(/"/g, '');
|
|
keys = keys.replace(/\s/g, '');
|
|
keys = keys.split(',');
|
|
return _.pick(obj, keys);
|
|
}
|
|
|
|
return obj;
|
|
});
|
|
|
|
query.response(dbEntry);
|
|
debug('#### Query end.\n');
|
|
} else {
|
|
query.response([]);
|
|
debug('#### Query end. Not found\n');
|
|
}
|
|
}
|
|
} else {
|
|
const tableName = query.sql.match(/from\s\"(\w+)\"/)[1];
|
|
query.response(this.db[tableName]);
|
|
}
|
|
} else if (query.method === 'insert') {
|
|
const tableName = query.sql.match(/into\s\"(\w+)\"/)[1];
|
|
let keys = query.sql.match(/\(([^)]+)\)/)[1],
|
|
entry = {};
|
|
|
|
keys = keys.replace(/"/g, '');
|
|
keys = keys.replace(/\s/g, '');
|
|
keys = keys.split(',');
|
|
|
|
_.each(keys, (key, index) => {
|
|
entry[key] = query.bindings[index];
|
|
});
|
|
|
|
if (!this.db[tableName]) {
|
|
this.db[tableName] = [];
|
|
}
|
|
|
|
this.db[tableName].push(entry);
|
|
query.response(entry);
|
|
debug('#### Query end.\n');
|
|
} else if (query.method === 'update') {
|
|
let tableName = query.sql.match(/update\s\"(\w+)\"/)[1],
|
|
where = query.sql.match(/where\s\"(\w+)\"\s\=\s\?/)[1],
|
|
andWhere = query.sql.match(/where\s\"\w+\"\s\=\s\?\sand\s\"(\w+)\"/),
|
|
valueWhere,
|
|
valueAndWhere,
|
|
dbEntry;
|
|
|
|
if (andWhere) {
|
|
andWhere = andWhere[1];
|
|
valueWhere = query.bindings.slice(1, -1)[0];
|
|
valueAndWhere = query.bindings.slice(-1)[0];
|
|
} else {
|
|
valueWhere = query.bindings.slice(-1)[0];
|
|
}
|
|
|
|
debug(tableName, where, valueWhere, andWhere, valueAndWhere, query.bindings);
|
|
|
|
dbEntry = _.find(this.db[tableName], ((existing) => {
|
|
if (existing[where] === valueWhere) {
|
|
if (andWhere) {
|
|
if (existing[andWhere] === valueAndWhere) {
|
|
return true;
|
|
}
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
}));
|
|
|
|
if (!dbEntry) {
|
|
query.response([]);
|
|
debug('#### Query end. Can\'t update - not found.\n');
|
|
} else {
|
|
let keys = query.sql.match(/set(.*)where/)[1],
|
|
entry = {};
|
|
|
|
keys = keys.match(/\"\w+\"/g).join(',');
|
|
keys = keys.replace(/"/g, '');
|
|
keys = keys.replace(/\s/g, '');
|
|
keys = keys.split(',');
|
|
|
|
debug('set', keys);
|
|
|
|
_.each(keys, (key, index) => {
|
|
entry[key] = query.bindings[index];
|
|
dbEntry[key] = entry[key];
|
|
});
|
|
|
|
query.response(entry);
|
|
debug('#### Query end.\n');
|
|
}
|
|
} else {
|
|
let tableName = query.sql.match(/from\s\"(\w+)\"/)[1],
|
|
where = query.sql.match(/where\s\"(\w+)\"\s\=\s\?/)[1],
|
|
andWhere = query.sql.match(/where\s\"\w+\"\s\=\s\?\sand\s\"(\w+)\"/),
|
|
valueWhere,
|
|
valueAndWhere;
|
|
|
|
valueWhere = query.bindings[0];
|
|
|
|
if (andWhere) {
|
|
andWhere = andWhere[1];
|
|
valueAndWhere = query.bindings[1];
|
|
}
|
|
|
|
debug(tableName, where, valueWhere, andWhere, valueAndWhere, query.bindings);
|
|
|
|
this.db[tableName] = this.db[tableName].filter((existing) => {
|
|
if (existing[where] === valueWhere) {
|
|
if (andWhere) {
|
|
if (existing[andWhere] === valueAndWhere) {
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
} else {
|
|
return true;
|
|
}
|
|
});
|
|
|
|
query.response([]);
|
|
}
|
|
});
|
|
}
|
|
|
|
return this.tracker;
|
|
}
|
|
|
|
unmock() {
|
|
this.tracker.uninstall();
|
|
mockKnex.unmock(knex);
|
|
}
|
|
}
|
|
|
|
module.exports = KnexMock;
|