tomjs
Version:
tomjs framework
761 lines (728 loc) • 35.9 kB
JavaScript
const require2 = require('tomjs/handlers/require2');
const mongoose = require2("mongoose");
const { join, extname } = require2('path');
const pluralize = require2('pluralize');
const _ = require2('lodash');
const appDir = require2('tomjs/handlers/dir')();
const { isArray, isObject, isFunction, isNumber, isString, select_fields, selectMustHave, readFile, valuesHideFields } = require2('tomjs/handlers/tools');
const pqlFiles = require2('tomjs/handlers/files');
const jsonTemplate = require2('tomjs/handlers/json_templater');
const LoadClass = require2('tomjs/handlers/load_class');
const models_cfg = require2('tomjs/configs')().models;
const BaseApiError = require2('tomjs/error/base_api_error');
const TEMPLATE_OPEN = '{{';
const TEMPLATE_END = '}}';
const REG_TEMPLATE_OPEN = new RegExp('"' + TEMPLATE_OPEN, 'g');
const REG_TEMPLATE_END = new RegExp(TEMPLATE_END + '"', 'g');
const TEMPLATE_OPEN2 = '{!';
const TEMPLATE_END2 = '!}'
const REG_TEMPLATE_OPEN2 = new RegExp('"' + TEMPLATE_OPEN2, 'g');
const REG_TEMPLATE_END2 = new RegExp(TEMPLATE_END2 + '"', 'g');
function myObjectAssign(target, source) {
let tempObj = {};
for (let idx in target) {
if (isObject(target[idx]) && isObject(source[idx])) {
tempObj[idx] = Object.assign(target[idx], source[idx]);
}
}
return Object.assign(target, source, tempObj);
}
function PopulateOptions(path, select, match, options, model, subPopulate, justOne) {
this.path = path;
this.match = match;
this.select = select;
this.options = options;
this.model = model;
if (typeof subPopulate === 'object') {
this.populate = subPopulate;
}
if (justOne != null) {
this.justOne = justOne;
}
this._docs = {};
}
function getRef(ref) {
if (typeof (ref) == 'function') {
return '';
} else { return ref; }
}
PopulateOptions.prototype.constructor = Object;
module.exports = function (inmongoose) {
if (inmongoose) { this.mongoose = inmongoose; } else {
this.mongoose = mongoose;
inmongoose = mongoose;
}
init();
return deepPopulatePlugin;
function DefaultOptions(_defaultDeepPopulateOptions, options) {
if (!isObject(options)) { options = {}; }
let _def = {};
if (isObject(_defaultDeepPopulateOptions)) {
_def = _defaultDeepPopulateOptions;
} else {
_def = models_cfg.pql.options;
}
if (options.max_deep === undefined) { options.max_deep = _def.max_deep === undefined ? 3 : _def.max_deep; }
if (options.default_limit === undefined) { options.default_limit = _def.default_limit === undefined ? 10 : _def.default_limit; }
if (options.default_limit_max === undefined) { options.default_limit_max = _def.default_limit_max === undefined ? 100 : _def.default_limit_max; }
if (options.is_guard === undefined) { options.is_guard = _def.is_guard === undefined ? true : _def.is_guard; }
if (options._deepPopulate_values === undefined) { options._deepPopulate_values = _def._deepPopulate_values === undefined ? '_deepPopulate_values' : _def._deepPopulate_values; }
if (options.getValues === undefined) { options.getValues = _def.getValues === undefined ? 'getValues' : _def.getValues; }
if (!isObject(options.locals)) { options.locals = _def.locals === undefined ? {} : _def.locals; }
else {
options.locals = Object.assign({}, options.locals, _def.locals);
}
if (options.aggregate_id === undefined) { options.aggregate_id = _def.aggregate_id === undefined ? 'id' : _def.aggregate_id; }
return options;
}
async function BuildPaths(conn, super_schema, schema, path_name, paths, options, deep = 0) {
options = options || {};
if (options.max_deep === undefined) { options.max_deep = 3; }
if (!isObject(options.locals)) { options.locals = {}; }
if (deep >= options.max_deep && !options.is_pql_file) {
return undefined;
}
let RE = new PopulateOptions();
if (deep === 0) {
let req = {}
let __USER_ID__ = { $type: "undefined" };
let __NOW__ = new Date();
let __NOW_TIMESTAMP__ = +new Date();
let __USER__ = null;
let ctx = null;
if (typeof (paths) == "object") {
try {
if (paths.app && paths.app.constructor && paths.app.constructor.name == "Application") {
ctx = paths;
try {
if (isObject(paths.auth) && isFunction(paths.auth.id) && paths.auth.id()) {
__USER_ID__ = paths.auth.id();
__USER__ = await paths.auth.user();
}
req = Object.assign({}, paths.request.query ? paths.request.query : {}, paths.request.body ? paths.request.body : {});
const pql_query = req[models_cfg.pql.ctx_body_query_field];
if (isString(pql_query) ? pql_query.trim() : pql_query) {
paths = pql_query;
}
else {
if (models_cfg.pql.auto_pql_file && isFunction(models_cfg.pql.auto_pql_file_function)) {
paths = await models_cfg.pql.auto_pql_file_function(ctx);
}
else {
paths = {};
}
}
} catch (error) { paths = {}; }
}
else {
options.is_pql_file = true;
}
}
catch (error) { }
}
if (typeof (paths) == "string" && paths.trim().length > 0) {
if (paths.trim()[0] == '{' && !models_cfg.pql.only_pql_file_mode) {
try {
paths = JSON.parse(paths);
} catch (err) {
throw new BaseApiError(BaseApiError.JSON_PARSE_ERROR, paths);
}
} else {
try {
if (extname(paths.trim()).length < 1) {
paths += '.pql';
}
// const template = await readFile(join(appDir, '..', models_cfg.pql.pql_public_path, paths), 'utf8');
const template = models_cfg.pql.pql_file_in_memory ? await pqlFiles(join(appDir, '..', models_cfg.pql.pql_public_path, paths), 'utf8')
: await readFile(join(appDir, '..', models_cfg.pql.pql_public_path, paths), 'utf8');
const locals = req[models_cfg.pql.ctx_body_pql_file_values_field] ? JSON.parse(req[models_cfg.pql.ctx_body_pql_file_values_field]) : {};
paths = JSON.parse(jsonTemplate(template, Object.assign({ __USER_ID__, __USER__, __NOW__, __NOW_TIMESTAMP__ }, options.locals, locals)));
options.is_guard = false;
options.is_pql_file = true;
} catch (err) {
throw new BaseApiError(BaseApiError.PQL_FILE_ERROR, 'PQL File:' + paths + " ,error:" + err.message);
}
}
}
else if (isObject(paths)) {
paths = JSON.parse(JSON.stringify(paths));
}
options.oldPaths = JSON.parse(JSON.stringify(paths));
}
if (options.is_guard === undefined) { options.is_guard = true; }
for (let i in paths) {
if (i === '$model' && typeof (paths[i]) == "string") {
RE.model = paths[i];
}
}
let model_name = RE.model ? RE.model : path_name;
if (!schema) {
if (!inmongoose.models[model_name]) {
let loadOK = true;
if (super_schema) {
let temp_ref = undefined;
if (super_schema.obj[model_name]) {
temp_ref = getRef(super_schema.obj[model_name].ref);
} else if (super_schema.virtuals[model_name]) {
temp_ref = getRef(super_schema.virtuals[model_name].options.ref);
}
if (temp_ref) {
RE.model = temp_ref;
if (!inmongoose.models[temp_ref]) {
let nModel = await LoadClass('model', temp_ref);
let nmodel = nModel.Model(conn);
schema = nModel.BuildSchema;
} else {
schema = inmongoose.models[temp_ref].schema;
}
}
} else {
try {
if (model_name.startsWith(models_cfg.belongs_to_many._belongs_to_many_head)) {
let allBelongsToMany = super_schema.methods.getAllBelongsToMany();
let i = _.findKey(allBelongsToMany, { belongs_to_many: model_name });
model_name = i ? allBelongsToMany[i].ref : model_name;
}
let mModel = await LoadClass('model', model_name);
let mmodel = mModel.Model(conn);
schema = mModel.BuildSchema;
} catch (e) { loadOK = false; }
}
} else {
schema = inmongoose.models[model_name];
}
}
let only_arr = [];
let except_arr = [];
let have_virtual_obj = false;
let virtual_obj = {};
for (let i in paths) {
if (!isObject(paths[i])) {
if (paths[i] === 1) {
const true_schema = schema.virtuals ? schema.methods.getRelationshipsVirtuals() : schema.schema.methods.getRelationshipsVirtuals();
if (schema && true_schema[i]) {
if (i == 'id') {
only_arr.push(i);
} else { paths[i] = {}; }
} else { only_arr.push(i); }
} else if (paths[i] < 1) {
except_arr.push(i);
}
}
}
if (super_schema && schema) {
for (let idx in super_schema.virtuals) {
if (super_schema.virtuals[idx].options.ref == (schema.getModelClassName || schema.methods.getModelClassName)()) {
virtual_obj[super_schema.virtuals[idx].options.foreignField] = 1; //添加 因有引用需要保留的字段
have_virtual_obj = true;
}
}
}
let allBelongsToMany = schema ? (((schema.getAllBelongsToMany || schema.methods?.getAllBelongsToMany) || schema.schema?.methods?.getAllBelongsToMany)()) : {};
for (let i in paths) {
if (isObject(paths[i])) {
let dqBelongsToMany = undefined;
switch (i) {
case '$match':
if (!options.is_guard || options.is_pql_file === true) {
if (deep <= 0 && models_cfg.pql.first_match_allow) {
RE.match = paths[i];
for (const key in RE.match) {
if (RE.match.hasOwnProperty(key) && key.trim().toLowerCase() === '$or') {
delete RE.match[key];
break;
}
}
}
else {
RE.match = paths[i];
}
}
break;
case '$options':
RE.options = paths[i];
break;
default:
let changeBelongsToManyModel = undefined;
if (allBelongsToMany[i]) {
let toMany = {};
let pivot = undefined;
if (paths[i][models_cfg.pql.pivot]) {
pivot = paths[i][models_cfg.pql.pivot];
delete paths[i][models_cfg.pql.pivot];
}
toMany[allBelongsToMany[i].populateField] = paths[i];
changeBelongsToManyModel = getRef(allBelongsToMany[i].ref);
delete paths[i];
dqBelongsToMany = Object.assign({}, allBelongsToMany[i]);
i = allBelongsToMany[i].belongs_to_many;
if (pivot !== undefined) {
Object.assign(toMany, pivot);
}
paths[i] = toMany;
}
if (isObject(schema)) {
if (schema.virtuals[i]) {
let localField = schema.virtuals[i].options.localField;
const lastIndex = localField.lastIndexOf('.');
let add_field = true;
if (lastIndex > -1) {
const localField_parent = localField.substring(0, lastIndex);
if (paths[localField] || paths[localField_parent]) {
add_field = false;
}
}
if (add_field) { virtual_obj[localField] = 1; }
have_virtual_obj = true;
}
}
paths[i] = await BuildPaths(conn, schema, undefined, i, paths[i], options, true, deep + 1);
if (dqBelongsToMany) {
myObjectAssign(paths[i], dqBelongsToMany);
}
if (changeBelongsToManyModel) {
paths[i].model = changeBelongsToManyModel;
}
if (paths[i] === undefined) { delete paths[i]; } else {
if (deep == 0) {
if (!RE.populate) { RE.populate = {}; }
paths[i].path = i;
if (paths[i].model === undefined && schema) {
if (schema.virtuals[i] && schema.virtuals[i].options) {
paths[i].model = getRef(schema.virtuals[i].options.ref);
} else if (schema.obj[i]) {
paths[i].model = getRef(schema.obj[i].ref);
}
}
RE.populate[i] = paths[i];
} else {
if (!RE.populate) { RE.populate = []; }
paths[i].path = i;
RE.populate.push(paths[i]);
}
}
break;
}
}
else {
if (i == '$must') {
RE.$must = paths[i];
}
}
}
if (deep !== 0 && options.default_limit && options.default_limit_max) {
if (!isObject(RE.options)) { RE.options = {}; }
if (RE.options.limit === undefined && !options.is_pql_file) { RE.options.limit = options.default_limit; }
if (RE.options.limit > options.default_limit_max && !options.is_pql_file) { RE.options.limit = options.default_limit_max; }
}
if (options.is_guard) {
if (schema) {
RE.select = select_fields(only_arr, except_arr, schema.methods.PopulateFields());
RE.select_old = Object.assign({}, RE.select);
if (have_virtual_obj) { selectMustHave(RE.select, virtual_obj); }
} else {
RE.select = { _id: 1 };
RE.select_old = Object.assign({}, RE.select);
}
} else {
RE.select = select_fields(only_arr, except_arr);
RE.select_old = Object.assign({}, RE.select);
if (have_virtual_obj) { selectMustHave(RE.select, virtual_obj); }
}
return RE;
}
function init() {
if (this.mongoose.Query.prototype.deepPopulate != null) {
return
}
this.mongoose.Query.prototype.deepPopulate = function (paths, options = {}) {
DefaultOptions(this.schema._defaultDeepPopulateOptions, options);
this._deepPopulatePaths = { paths, options };
return this;
}
this.mongoose.Query.prototype.pql = this.mongoose.Query.prototype.deepPopulate;
};
function aggregateRunDeepPopulate(next) {
let pipeline_len = this._pipeline.length;
let paths, options;
let have_pql = false;
for (let i = pipeline_len - 1; i > 0; i--) {
if (this._pipeline[i].$pql) {
paths = this._pipeline[i].$pql;
have_pql = true;
this._pipeline.splice(i, 1);
continue;
}
if (this._pipeline[i].$pql_options) {
options = this._pipeline[i].$pql_options;
this._pipeline.splice(i, 1);
}
}
pipeline_len = this._pipeline.length;
for (let i = pipeline_len - 1; i > 0; i--) {
if (this._pipeline[i].$group) {
let myoptions = Object.assign({}, options);
DefaultOptions(this._model.schema._defaultDeepPopulateOptions, myoptions);
if (this._pipeline[i].$group[myoptions.aggregate_id] === undefined) {
this._pipeline[i].$group[myoptions.aggregate_id] = { $min: "$_id" };
}
}
}
if (have_pql !== false) {
this._deepPopulatePaths = { paths, options };
}
if (next) { return next(); }
}
async function paginate($this, page_or_ctx, limit) {
let page = 0;
if (isObject(page_or_ctx) && isObject(page_or_ctx[models_cfg.pagination.ctx_field])) {
if (page_or_ctx[models_cfg.pagination.ctx_field][models_cfg.pagination.pageindex]) {
page = parseInt(page_or_ctx[models_cfg.pagination.ctx_field][models_cfg.pagination.pageindex]);
}
if ((limit === null || limit === undefined)
&& page_or_ctx[models_cfg.pagination.ctx_field][models_cfg.pagination.pagesize]
) { limit = parseInt(page_or_ctx[models_cfg.pagination.ctx_field][models_cfg.pagination.pagesize]); }
}
else { page = parseInt(page_or_ctx); }
if (isNaN(limit)) {
limit = models_cfg.pagination.pagesize_default;
limit = isNaN(limit) ? 10 : limit;
}
const limit_min = models_cfg.pagination.pagesize_min;
if (!isNaN(limit_min)) {
limit = limit < limit_min ? limit_min : limit;
}
const limit_max = models_cfg.pagination.pagesize_max;
if (!isNaN(limit_max)) {
limit = limit >= limit_max ? limit_max : limit;
}
if (limit < 1) { limit = 1; }
page = isNaN(page) ? 0 : page;
page = page < 1 ? 1 : page;
let query = $this;
const model = $this.model;
const total = await model.countDocuments(query._conditions);
const max_page = parseInt(total / limit, 10) + (total % limit == 0 ? 0 : 1);
const skipFrom = (page * limit) - limit;
query = query.skip(skipFrom).limit(limit);
$this[models_cfg.pagination.pagination_info] = { page, max_page, limit, total };
};
async function runDeepPopulate(next) {
let RE = undefined;
if (this._deepPopulatePaths && this._deepPopulatePaths_End === undefined) {
RE = await BuildPaths(this.model.db || this.db, undefined, this.model.schema || this.schema, '',
this._deepPopulatePaths.paths,
this._deepPopulatePaths.options,
0);
this._deepPopulatePaths_End = {};
this._deepPopulatePaths_End.re = RE;
this._deepPopulatePaths_End.options = this._deepPopulatePaths.options;
delete this._deepPopulatePaths;
if (isObject(RE.match)) {
this._conditions = Object.assign(this._conditions || {}, RE.match);
if (isObject(this[models_cfg.pagination.pagination_info])) {
await paginate(this, this[models_cfg.pagination.pagination_info].page, this[models_cfg.pagination.pagination_info].limit);
}
}
if (isObject(RE.select)) {
for (let idx in RE.select) {
RE.select[idx] = RE.select[idx] <= 0 ? 0 : 1;
}
this._fields = Object.assign(this._fields || {}, RE.select);
}
if (isObject(RE.options)) { this.options = Object.assign(this.options || {}, RE.options); }
if (isObject(RE.populate) && isObject(this._mongooseOptions)) {
this._mongooseOptions.populate = Object.assign(this._mongooseOptions.populate || {}, RE.populate);
}
}
if (next) { next(); }
return RE;
};
function field_check(EndVal, values) {
if (isObject(EndVal.select) && isObject(values)) {
let is_only = true;
for (let idx in EndVal.select) {
is_only = EndVal.select[idx] == 1;
break;
}
if (is_only) {
if (isObject(EndVal.populate)) {
for (let idx in EndVal.populate) {
EndVal.select[idx] = 1;
EndVal.select_old[idx] = 1;
}
} else if (isArray(EndVal.populate)) {
let populate_len = EndVal.populate.length;
for (let i = 0; i < populate_len; i++) {
EndVal.select[EndVal.populate[i].path] = 1;
EndVal.select_old[EndVal.populate[i].path] = 1;
}
}
}
for (let idx in values) {
if (is_only) {
if ((!EndVal.select[idx] && !EndVal.select[models_cfg.belongs_to_many._belongs_to_many_head + idx]) ||
(!EndVal.select_old[idx])) {
delete values[idx];
if (values[idx] !== undefined) {
if (values.prototype[idx] !== undefined) { delete values.prototype[idx]; }
if (values.__proto__[idx] !== undefined) { delete values.__proto__[idx]; }
}
}
} else {
if (EndVal.select[idx] || EndVal.select_old[idx]) {
delete values[idx];
if (values[idx] !== undefined) {
if (values.prototype[idx] !== undefined) { delete values.prototype[idx]; }
if (values.__proto__[idx] !== undefined) { delete values.__proto__[idx]; }
}
}
}
}
}
if (isObject(EndVal.populate)) {
for (let idx in EndVal.populate) {
if (isObject(values[idx])) {
field_check(EndVal.populate[idx], values[idx]);
} else if (isArray(values[idx])) {
let values_len = values[idx].length;
for (let i = 0; i < values_len; i++) {
if (isObject(values[idx][i])) {
field_check(EndVal.populate[idx], values[idx][i]);
}
}
}
}
} else if (isArray(EndVal.populate)) {
let populate_len = EndVal.populate.length;
for (let i = 0; i < populate_len; i++) {
let path = undefined;
if (EndVal.populate[i].path.startsWith(models_cfg.belongs_to_many._belongs_to_many_head)) {
path = EndVal.populate[i].path.substring(models_cfg.belongs_to_many._belongs_to_many_head.length);
if (isArray(EndVal.populate[i].populate) && EndVal.populate[i].populate.length > 0) {
let length = EndVal.populate[i].populate.length;
let singular_path = pluralize.singular(path);
for (let j = 0; j < length; j++) {
if (singular_path == pluralize.singular(EndVal.populate[i].populate[j].path)) {
EndVal.populate[i] = EndVal.populate[i].populate[j];
EndVal.populate[i].path = path;
break;
}
}
}
} else {
path = EndVal.populate[i].path;
}
if (isArray(values[path])) {
let values_len = values[path].length;
for (let j = 0; j < values_len; j++) { field_check(EndVal.populate[i], values[path][j]); }
} else if (isObject(values[path])) {
field_check(EndVal.populate[i], values[path]);
}
}
}
}
function NumberIsOK(object, number) {
if (!isObject(object)) { return false; }
number = parseInt(number, 10);
let re = "";
for (const key in object) {
const element = parseInt(object[key], 10);
switch (key) {
case '$eq': {
re = number == element;
break;
}
case '$ne': {
re = number != element;
break;
}
case '$gt': {
re = number > element;
break;
}
case '$gte': {
re = number >= element;
break;
}
case '$lt': {
re = number < element;
break;
}
case '$lte': {
re = number <= element;
break;
}
default:
re = false;
break;
}
if (!re) { return false; }
}
return re;
}
function must_check(value, Paths, __DB_TOP__, __DB_PRE__) {
if (isObject(Paths.$must)) {
//判断对象中是否有未解析的变量
let input = JSON.stringify(Paths.$must);
let boObjFind = false;
if (input.indexOf(TEMPLATE_OPEN) !== -1) {
boObjFind = true;
input = input.replace(REG_TEMPLATE_OPEN, TEMPLATE_OPEN).replace(REG_TEMPLATE_END, TEMPLATE_END);
}
else if (input.indexOf(TEMPLATE_OPEN2) !== -1) {
boObjFind = true;
input = input.replace(REG_TEMPLATE_OPEN2, TEMPLATE_OPEN2).replace(REG_TEMPLATE_END2, TEMPLATE_END2);
}
if (boObjFind) {
Paths.$must = input;
}
}
if (isString(Paths.$must)) {
Paths.$must = JSON.parse(jsonTemplate(Paths.$must, { __DB_TOP__, __DB_PRE__, __DB__: __DB_PRE__ }));
if (Paths.$must === "true") { Paths.$must = true; }
else if (Paths.$must === "false") { Paths.$must = false; }
else if (isString(Paths.$must)) { Paths.$must = parseInt(Paths.$must, 10); }
}
if (Paths.$must === true || Paths.$must === false || isNumber(Paths.$must) || isObject(Paths.$must) || isArray(Paths.$must)) {
if (isArray(value)) {
const len = value.length;
for (let index = len - 1; index >= 0; index--) {
if (value[index] === null || value[index] === undefined || value[index] === Symbol.for('$no_must')) {
value.splice(index, 1);
}
}
}
if ((Paths.$must === false || Paths.$must === 0) && value !== null && value !== undefined && (isArray(value) && value.length > 0)) {
return Symbol.for('$no_must');
}
if (Paths.$must === true && (value === null || (isArray(value) && value.length < 1))) {
return Symbol.for('$no_must');
}
if (isNumber(Paths.$must) && Paths.$must > 0) {
if (Paths.$must === 1 && (value === null || value === undefined || (isArray(value) && value.length != 1))) {
return Symbol.for('$no_must');
}
else if (!isArray(value) || (isArray(value) && value.length != Paths.$must)) {
return Symbol.for('$no_must');
}
}
if (isObject(Paths.$must)) {
const len = isArray(value) ? value.length : 0;
if (!NumberIsOK(Paths.$must, len)) {
return Symbol.for('$no_must');
}
}
if (isArray(Paths.$must)) {
const len = isArray(value) ? value.length : 0;
for (let index = 0; index < Paths.$must.length; index++) {
if (!NumberIsOK(Paths.$must[index], len)) {
return Symbol.for('$no_must');
}
}
}
}
if (value) {
for (const key in Paths) {
if (isObject(Paths[key]) && key[0] != '$') {
const populate = Paths[key];
if (must_check(value[key], populate, __DB_TOP__, value) === Symbol.for('$no_must')) {
return undefined;
}
}
}
}
return value;
}
function getValues(values, EndRE, hideFields) {
if (isObject(values) && typeof (values.toJSON) == "function") {
let value = values.toJSON();
field_check(EndRE, value);
const __DB_TOP__ = JSON.parse(JSON.stringify(value));
if (isObject(hideFields)) { value = valuesHideFields(hideFields, value); }
let re = must_check(value, EndRE.oldPaths, __DB_TOP__, __DB_TOP__);
if (re === Symbol.for('$no_must')) { re = undefined; }
return re;
} else if (isArray(values)) {
let len = values.length;
let one = undefined;
let all = [];
for (let i = 0; i < len; i++) {
one = values[i];
if (isObject(one) && typeof (one.toJSON) == "function") {
let value = one.toJSON();
field_check(EndRE, value);
const __DB_TOP__ = JSON.parse(JSON.stringify(value));
if (isObject(hideFields)) { value = valuesHideFields(hideFields, value); }
const val = must_check(value, EndRE.oldPaths, __DB_TOP__, __DB_TOP__);
if (val !== undefined && val !== Symbol.for('$no_must')) { all.push(val); }
}
}
let re = undefined;
if (values[models_cfg.pagination.pagination_info]) {
re = { data: all };
re[models_cfg.pagination.pagination_info] = values[models_cfg.pagination.pagination_info];
} else {
if (models_cfg.pql.all_in_data) {
re = { data: all };
} else { re = all; }
}
return re;
}
}
function endDeepPopulate(values) {
if (values) {
if (this._deepPopulatePaths_End) {
const EndRE = this._deepPopulatePaths_End.re;
EndRE.oldPaths = this._deepPopulatePaths_End.options.oldPaths;
const options = this._deepPopulatePaths_End.options;
delete this._deepPopulatePaths_End;
if (options._deepPopulate_values) {
values[options._deepPopulate_values] = getValues(values, EndRE);
values[options.getValues] = getValues.bind(this, values, EndRE);
}
}
}
}
async function aggregateEndDeepPopulateOne($this, doc) {
const options = DefaultOptions($this._model.schema._defaultDeepPopulateOptions, $this._deepPopulatePaths.options);
const model = $this._model;
const obj = await model.findById(doc[options.aggregate_id]).pql($this._deepPopulatePaths.paths, $this._deepPopulatePaths.options);
Object.assign(doc, obj.getValues());
}
async function aggregateEndDeepPopulate(values) {
if (this._deepPopulatePaths) {
if (isObject(this._deepPopulatePaths.paths)) {
if (this._deepPopulatePaths.paths._id === undefined) {
this._deepPopulatePaths.paths._id = 1;
}
}
if (isObject(values)) {
await aggregateEndDeepPopulateOne(this, values);
} else if (isArray(values)) {
const len = values.length;
for (let i = 0; i < len; i++) {
await aggregateEndDeepPopulateOne(this, values[i]);
}
}
}
}
function deepPopulatePlugin(schema, defaultOptions) {
schema._defaultDeepPopulateOptions = defaultOptions;
schema.pre('findOne', runDeepPopulate)
.pre('find', runDeepPopulate)
.pre('aggregate', aggregateRunDeepPopulate)
.post('findOne', endDeepPopulate)
.post('find', endDeepPopulate)
.post('aggregate', aggregateEndDeepPopulate);
schema.methods.deepPopulate = async function (paths, options = {}) { //查询后再填充
DefaultOptions(schema._defaultDeepPopulateOptions, options);
this._deepPopulatePaths = { paths, options };
const RE = await runDeepPopulate.call(this, null);
const values = await this.populate(_.values(RE.populate));
endDeepPopulate.call(this, values);
return values;
};
schema.methods.pql = schema.methods.deepPopulate;
};
};