objection
Version:
An SQL-friendly ORM for Node.js
165 lines (133 loc) • 4.04 kB
JavaScript
;
const { QueryBuilderOperation } = require('./QueryBuilderOperation');
const { StaticHookArguments } = require('../StaticHookArguments');
const { isPromise, after, afterReturn } = require('../../utils/promiseUtils');
const { isObject } = require('../../utils/objectUtils');
class FindOperation extends QueryBuilderOperation {
onBefore2(builder, result) {
return afterReturn(callStaticBeforeFind(builder), result);
}
onAfter3(builder, results) {
const opt = builder.findOptions();
if (opt.dontCallFindHooks) {
return results;
} else {
return callAfterFind(builder, results);
}
}
}
function callStaticBeforeFind(builder) {
const args = StaticHookArguments.create({ builder });
return builder.modelClass().beforeFind(args);
}
function callAfterFind(builder, result) {
const opt = builder.findOptions();
const maybePromise = callInstanceAfterFind(builder.context(), result, opt.callAfterFindDeeply);
return after(maybePromise, () => callStaticAfterFind(builder, result));
}
function callStaticAfterFind(builder, result) {
const args = StaticHookArguments.create({ builder, result });
const maybePromise = builder.modelClass().afterFind(args);
return after(maybePromise, (maybeResult) => {
if (maybeResult === undefined) {
return result;
} else {
return maybeResult;
}
});
}
function callInstanceAfterFind(ctx, results, deep) {
if (Array.isArray(results)) {
if (results.length === 1) {
return callAfterFindForOne(ctx, results[0], results, deep);
} else {
return callAfterFindArray(ctx, results, deep);
}
} else {
return callAfterFindForOne(ctx, results, results, deep);
}
}
function callAfterFindArray(ctx, results, deep) {
if (results.length === 0 || !isObject(results[0])) {
return results;
}
const mapped = new Array(results.length);
let containsPromise = false;
for (let i = 0, l = results.length; i < l; ++i) {
mapped[i] = callAfterFindForOne(ctx, results[i], results[i], deep);
if (isPromise(mapped[i])) {
containsPromise = true;
}
}
if (containsPromise) {
return Promise.all(mapped);
} else {
return mapped;
}
}
function callAfterFindForOne(ctx, model, result, deep) {
if (!isObject(model) || !model.$isObjectionModel) {
return result;
}
if (deep) {
const results = [];
const containsPromise = callAfterFindForRelations(ctx, model, results);
if (containsPromise) {
return Promise.all(results).then(() => {
return doCallAfterFind(ctx, model, result);
});
} else {
return doCallAfterFind(ctx, model, result);
}
} else {
return doCallAfterFind(ctx, model, result);
}
}
function callAfterFindForRelations(ctx, model, results) {
const keys = Object.keys(model);
let containsPromise = false;
for (let i = 0, l = keys.length; i < l; ++i) {
const key = keys[i];
const value = model[key];
if (isRelation(value)) {
const maybePromise = callInstanceAfterFind(ctx, value, true);
if (isPromise(maybePromise)) {
containsPromise = true;
}
results.push(maybePromise);
}
}
return containsPromise;
}
function isRelation(value) {
return (
(isObject(value) && value.$isObjectionModel) ||
(isNonEmptyObjectArray(value) && value[0].$isObjectionModel)
);
}
function isNonEmptyObjectArray(value) {
return Array.isArray(value) && value.length > 0 && isObject(value[0]);
}
function doCallAfterFind(ctx, model, result) {
const afterFind = getAfterFindHook(model);
if (afterFind !== null) {
const maybePromise = afterFind.call(model, ctx);
if (isPromise(maybePromise)) {
return maybePromise.then(() => result);
} else {
return result;
}
} else {
return result;
}
}
function getAfterFindHook(model) {
if (model.$afterFind !== model.$objectionModelClass.prototype.$afterFind) {
return model.$afterFind;
} else {
return null;
}
}
module.exports = {
FindOperation,
};