Comparing version 1.13.24 to 1.13.25
@@ -28,2 +28,3 @@ /// <reference types="fibjs" /> | ||
where: { type: Function } | ||
join_where: { type: Function } | ||
findby: { type: Function } | ||
@@ -214,3 +215,3 @@ skip: { type: Function } | ||
where?: string | FibApp.ReqWhere | ||
// findby?: FibApp.ReqFindByItem|FibApp.ReqFindByItem[] | ||
join_where?: FibApp.ReqWhere | ||
findby?: FibApp.ReqFindByItem | ||
@@ -217,0 +218,0 @@ keys?: string | string[] |
@@ -103,2 +103,3 @@ /// <reference types="fibjs" /> | ||
// @deprecated, use orignal Model's field `associations` | ||
extends: FibAppOrmModelExtendsInfoHash; | ||
@@ -105,0 +106,0 @@ } |
@@ -13,2 +13,3 @@ /// <reference types="fibjs" /> | ||
where?: FxSqlQuerySubQuery.SubQueryConditions | ||
options?: FxOrmModel.ModelOptions__Findby | ||
} | ||
@@ -15,0 +16,0 @@ |
v1.13.24 / 2019-03-07 | ||
v1.13.25 / 2019-03-16 | ||
================== | ||
* support use `join_where` option in query for has-many assoc. | ||
* apply model's field `associations`. | ||
* normalize test case code. | ||
* make mysql as default test driver; fix error of test case in mysql. | ||
* 1.13.25-dev | ||
* upgrade @fxjs/orm. apply its feature about literal where conditions. | ||
v1.13.24 / 2019-03-07 | ||
===================== | ||
* Release v1.13.24 | ||
* code clean. | ||
@@ -6,0 +17,0 @@ * code clean. |
/// <reference types="@fxjs/orm" /> | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const ORM = require("@fxjs/orm"); | ||
const Helpers = ORM.Helpers; | ||
const err_info_1 = require("../utils/err_info"); | ||
@@ -9,3 +11,2 @@ const _find = require("../utils/find"); | ||
const ormUtils = require("../utils/orm"); | ||
const orm_assoc_1 = require("../utils/orm-assoc"); | ||
const query_1 = require("../utils/query"); | ||
@@ -27,3 +28,3 @@ function map_ro_result(ro) { | ||
}; | ||
const _createBy = cls.extends[spec_keys['createdBy']]; | ||
const _createBy = cls.associations[spec_keys['createdBy']]; | ||
let _opt; | ||
@@ -36,3 +37,3 @@ let instances = []; | ||
const ext_d = {}; | ||
for (const k in cls.extends) { | ||
for (const k in cls.associations) { | ||
if (d[k] !== undefined) { | ||
@@ -47,3 +48,3 @@ ext_d[k] = d[k]; | ||
if (_createBy !== undefined) { | ||
_opt = Object.keys(orm_assoc_1.get_one_association_item(o, spec_keys['createdBy']).field)[0]; | ||
_opt = Object.keys(Helpers.getOneAssociationItemFromInstanceByExtname(o, spec_keys['createdBy']).field)[0]; | ||
o[_opt] = req.session.id; | ||
@@ -94,3 +95,3 @@ } | ||
let delr = !orm.settings.get(`rest.model.keep_association.put.${cls.model_name}`); | ||
for (const k in cls.extends) { | ||
for (const k in cls.associations) { | ||
const r = data[k]; | ||
@@ -129,3 +130,3 @@ if (r !== undefined) { | ||
return { | ||
success: query_1.found_result_selector(_find(req, cls.find()), !query_1.is_count_required(req.query) ? 'results' : '') | ||
success: query_1.found_result_selector(_find(req, cls.find.bind(cls), { bmodel: cls }), !query_1.is_count_required(req.query) ? 'results' : '') | ||
}; | ||
@@ -132,0 +133,0 @@ }; |
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const util = require("util"); | ||
const ORM = require("@fxjs/orm"); | ||
const Helpers = ORM.Helpers; | ||
const _find = require("../utils/find"); | ||
const err_info_1 = require("../utils/err_info"); | ||
const util = require("util"); | ||
const ormUtils = require("../utils/orm"); | ||
const checkout_acl_1 = require("../utils/checkout_acl"); | ||
const filter_1 = require("../utils/filter"); | ||
const get_1 = require("../utils/get"); | ||
const ormUtils = require("../utils/orm"); | ||
const orm_assoc_1 = require("../utils/orm-assoc"); | ||
@@ -20,4 +22,4 @@ const query_1 = require("../utils/query"); | ||
api.eput = (req, orm, cls, id, extend, rid, data) => { | ||
const rel_model = cls.extends[extend]; | ||
if (rel_model === undefined) | ||
const rel_assoc_info = cls.associations[extend]; | ||
if (rel_assoc_info === undefined) | ||
return err_info_1.err_info(4040001, { | ||
@@ -38,3 +40,3 @@ classname: extend | ||
riobj.inst['extra'] = data.extra; | ||
const many_assoc = orm_assoc_1.check_hasmany_extend_extraprops(iobj.inst, extend); | ||
const many_assoc = orm_assoc_1.check_hasmanyassoc_with_extraprops(iobj.inst, extend); | ||
if (many_assoc) { | ||
@@ -52,8 +54,8 @@ orm_assoc_1.extra_save(iobj.inst, riobj.inst, many_assoc, data.extra, true); | ||
api.elink = (req, orm, cls, id, extend, data) => { | ||
const rel_model = cls.extends[extend]; | ||
if (rel_model === undefined) | ||
const rel_assoc_info = cls.associations[extend]; | ||
if (rel_assoc_info === undefined) | ||
return err_info_1.err_info(4040001, { | ||
classname: extend | ||
}); | ||
if (rel_model.type === 'extendsTo') | ||
if (rel_assoc_info.type === 'extendsTo') | ||
return api.eput(req, orm, cls, id, extend, undefined, Object.assign({}, data)); | ||
@@ -71,4 +73,4 @@ const obj = get_1._get(cls, id, req.session, "write"); | ||
classname: extend | ||
}, rel_model.model.cid); | ||
const robj = get_1._get(rel_model.model, rid, req.session, "read"); | ||
}, rel_assoc_info.association.model.cid); | ||
const robj = get_1._get(rel_assoc_info.association.model, rid, req.session, "read"); | ||
if (robj.error) | ||
@@ -78,11 +80,16 @@ return robj; | ||
let _opt; | ||
switch (rel_model.type) { | ||
switch (rel_assoc_info.type) { | ||
case 'hasOne': | ||
_opt = orm_assoc_1.get_one_association_item(obj.inst, extend).setAccessor; | ||
_opt = Helpers.getOneAssociationItemFromInstanceByExtname(obj.inst, extend).setAccessor; | ||
break; | ||
case 'hasMany': | ||
_opt = Helpers.getManyAssociationItemFromInstanceByExtname(obj.inst, extend).addAccessor; | ||
default: | ||
_opt = orm_assoc_1.get_many_association_item(obj.inst, extend).addAccessor; | ||
break; | ||
} | ||
if (!_opt) | ||
return err_info_1.err_info(4040003, { | ||
extend: extend, | ||
classname: cls.model_name, | ||
}, rel_assoc_info.association.model.cid); | ||
obj.inst[_opt + 'Sync'].call(obj.inst, robj.inst); | ||
@@ -97,4 +104,4 @@ return { | ||
api.epost = (req, orm, cls, id, extend, data) => { | ||
const rel_model = cls.extends[extend]; | ||
if (rel_model === undefined) | ||
const rel_assoc_info = cls.associations[extend]; | ||
if (rel_assoc_info === undefined) | ||
return err_info_1.err_info(4040001, { | ||
@@ -122,6 +129,5 @@ classname: extend | ||
}; | ||
const is_extendsTo = rel_model.type === 'extendsTo'; | ||
const extendsToAssoc = is_extendsTo ? orm_assoc_1.get_extendsto_association_item(obj.inst, extend) : null; | ||
const key_model = is_extendsTo ? rel_model.assoc_model : rel_model.model; | ||
const _createBy = key_model.extends[spec_keys['createdBy']]; | ||
const is_extendsTo = rel_assoc_info.type === 'extendsTo'; | ||
const key_model = rel_assoc_info.association.model; | ||
const _createBy = key_model.associations[spec_keys['createdBy']]; | ||
let _opt; | ||
@@ -132,3 +138,3 @@ let ros = []; | ||
d = filter_1.filter(d, acl); | ||
const extra_many_assoc = orm_assoc_1.check_hasmany_extend_extraprops(obj.inst, extend) || null; | ||
const extra_many_assoc = orm_assoc_1.check_hasmanyassoc_with_extraprops(obj.inst, extend) || null; | ||
rextdata_extras.push({ extra_many_assoc, extra: d.extra || null }); | ||
@@ -141,3 +147,3 @@ delete d.extra; | ||
if (_createBy !== undefined) { | ||
_opt = Object.keys(orm_assoc_1.get_one_association_item(ro, spec_keys['createdBy']).field)[0]; | ||
_opt = Object.keys(Helpers.getOneAssociationItemFromInstanceByExtname(ro, spec_keys['createdBy']).field)[0]; | ||
ro[_opt] = req.session.id; | ||
@@ -152,6 +158,4 @@ } | ||
} | ||
else { | ||
} | ||
const r_ext_d = {}; | ||
for (const k in key_model.extends) { | ||
for (const k in key_model.associations) { | ||
if (d[k] !== undefined) { | ||
@@ -176,16 +180,13 @@ r_ext_d[k] = d[k]; | ||
if (!key_model.reversed) { | ||
let _opt, assoc; | ||
switch (rel_model.type) { | ||
let _opt, assoc = Helpers.getAssociationItemFromInstanceByExtname(rel_assoc_info.type, obj.inst, extend); | ||
switch (rel_assoc_info.type) { | ||
default: | ||
break; | ||
case 'extendsTo': | ||
assoc = extendsToAssoc; | ||
_opt = assoc.setAccessor; | ||
break; | ||
case 'hasOne': | ||
assoc = orm_assoc_1.get_one_association_item(obj.inst, extend); | ||
_opt = assoc.setAccessor; | ||
break; | ||
case 'hasMany': | ||
assoc = orm_assoc_1.get_many_association_item(obj.inst, extend); | ||
_opt = assoc.addAccessor; | ||
@@ -215,9 +216,9 @@ break; | ||
api.efind = (req, orm, cls, id, extend) => { | ||
const rel_model = cls.extends[extend]; | ||
if (rel_model === undefined) | ||
const rel_assoc_info = cls.associations[extend]; | ||
if (rel_assoc_info === undefined) | ||
return err_info_1.err_info(4040001, { | ||
classname: extend | ||
}); | ||
if ((rel_model.type === 'hasOne' && !rel_model.reversed) | ||
|| rel_model.type === 'extendsTo') | ||
if ((rel_assoc_info.type === 'hasOne' && !rel_assoc_info.association.reversed) | ||
|| rel_assoc_info.type === 'extendsTo') | ||
return api.eget(req, orm, cls, id, extend); | ||
@@ -238,6 +239,10 @@ let obj; | ||
if (!checkout_acl_1.checkout_obj_acl(req.session, 'find', obj.inst, extend)) | ||
return err_info_1.err_info(4030001, { classname: cls.model_name }, rel_model.model.cid); | ||
let _association = orm_assoc_1.get_association_item_by_reltype(rel_model.type, obj.inst, extend); | ||
return err_info_1.err_info(4030001, { classname: cls.model_name }, rel_assoc_info.association.model.cid); | ||
const _association = Helpers.getAssociationItemFromInstanceByExtname(rel_assoc_info.type, obj.inst, extend); | ||
return { | ||
success: query_1.found_result_selector(_find(req, obj.inst[_association.getAccessor].call(obj.inst).find(), obj.inst, extend), !query_1.is_count_required(req.query) ? 'results' : '') | ||
success: query_1.found_result_selector(_find(req, obj.inst[_association.getAccessor].bind(obj.inst), { | ||
bmodel: obj.inst.model(), | ||
binstance: obj.inst, | ||
extend | ||
}), !query_1.is_count_required(req.query) ? 'results' : '') | ||
}; | ||
@@ -263,19 +268,20 @@ }; | ||
ormUtils.attach_internal_api_requestinfo_to_instance(robj.inst, { data: null, req_info: req }); | ||
const rel_model = cls.extends[extend]; | ||
switch (rel_model.type) { | ||
const rel_assoc_info = cls.associations[extend]; | ||
const rel_type = rel_assoc_info.type; | ||
switch (rel_type) { | ||
default: | ||
throw `invalid rel_model.type ${rel_model.type}`; | ||
throw `invalid rel_assoc_info.type ${rel_type}`; | ||
case 'extendsTo': | ||
robj.base[orm_assoc_1.get_extendsto_association_item(robj.base, extend).delAccessor + 'Sync'].call(robj.base); | ||
robj.base[Helpers.getExtendsToAssociationItemFromInstanceByExtname(robj.base, extend).delAccessor + 'Sync'].call(robj.base); | ||
break; | ||
case 'hasOne': | ||
if (rel_model.reversed) | ||
if (rel_assoc_info.association.reversed) | ||
return err_info_1.err_info(4040003, { | ||
extend: extend, | ||
classname: rel_model.model.model_name | ||
}, rel_model.model.cid); | ||
robj.base[orm_assoc_1.get_one_association_item(robj.base, extend).delAccessor + 'Sync'].call(robj.base); | ||
classname: rel_assoc_info.association.model.model_name | ||
}, rel_assoc_info.association.model.cid); | ||
robj.base[Helpers.getOneAssociationItemFromInstanceByExtname(robj.base, extend).delAccessor + 'Sync'].call(robj.base); | ||
break; | ||
case 'hasMany': | ||
robj.base[orm_assoc_1.get_many_association_item(robj.base, extend).delAccessor + 'Sync'].call(robj.base, robj.inst); | ||
robj.base[Helpers.getManyAssociationItemFromInstanceByExtname(robj.base, extend).delAccessor + 'Sync'].call(robj.base, robj.inst); | ||
break; | ||
@@ -282,0 +288,0 @@ } |
@@ -22,2 +22,5 @@ const util = require("util"); | ||
}, | ||
join_where: { | ||
type: GraphQLJSON | ||
}, | ||
findby: { | ||
@@ -36,6 +39,6 @@ type: GraphQLJSON | ||
}; | ||
function get_extend_paging_unique_name(m, rel_model, extend) { | ||
if (rel_model.type === 'hasOne' && rel_model.reversed) | ||
return `extend_paging__reverse_${rel_model.model.model_name}_${rel_model.type}_${extend}_${m.model_name}`; | ||
return `extend_paging__${m.model_name}_${rel_model.type}_${extend}_${rel_model.model.model_name}`; | ||
function get_extend_paging_unique_name(m, rel_assoc_info, extend) { | ||
if (rel_assoc_info.type === 'hasOne' && rel_assoc_info.association.reversed) | ||
return `extend_paging__reverse_${rel_assoc_info.association.model.model_name}_${rel_assoc_info.type}_${extend}_${m.model_name}`; | ||
return `extend_paging__${m.model_name}_${rel_assoc_info.type}_${extend}_${rel_assoc_info.association.model.model_name}`; | ||
} | ||
@@ -187,9 +190,10 @@ module.exports = function (app, ormInstance) { | ||
} | ||
var _extends = m.extends; | ||
for (var f in _extends) { | ||
var rel_model = _extends[f]; | ||
if (rel_model.type !== 'extendsTo' && !rel_model.model) { | ||
throw `association ${f} defined for model ${m.model_name} but no valid related model, detailed information: \n ${JSON.stringify(rel_model, null, '\t')}`; | ||
var _associations = m.associations; | ||
for (var f in _associations) { | ||
var rel_assoc_info = _associations[f]; | ||
if (rel_assoc_info.type !== 'extendsTo' && !rel_assoc_info.association.model) { | ||
throw `association ${f} defined for model ${m.model_name} but no valid related model, detailed information: \n ${JSON.stringify(rel_assoc_info, null, '\t')}`; | ||
} | ||
switch (rel_model.type) { | ||
const assoc_model = rel_assoc_info.association.model; | ||
switch (rel_assoc_info.type) { | ||
default: | ||
@@ -199,3 +203,3 @@ break; | ||
fields[f] = { | ||
type: types[rel_model.assoc_model.model_name].type, | ||
type: types[assoc_model.model_name].type, | ||
resolve: eget_resolve(m, f) | ||
@@ -205,5 +209,5 @@ }; | ||
case 'hasOne': | ||
if (!rel_model.reversed) { | ||
if (!rel_assoc_info.association.reversed) { | ||
fields[f] = { | ||
type: types[rel_model.model.model_name].type, | ||
type: types[assoc_model.model_name].type, | ||
resolve: eget_resolve(m, f) | ||
@@ -215,7 +219,7 @@ }; | ||
{ | ||
let type_has_many = new graphql.GraphQLList(types[rel_model.model.model_name].type); | ||
let type_has_many = new graphql.GraphQLList(types[assoc_model.model_name].type); | ||
let type_has_many_mixin_extra = null; | ||
let has_many_association = null; | ||
if (!no_extra_fields) { | ||
has_many_association = orm_assoc_1.check_hasmany_extend_extraprops((new m()), f); | ||
has_many_association = orm_assoc_1.check_hasmanyassoc_with_extraprops((new m()), f); | ||
if (has_many_association) { | ||
@@ -225,3 +229,3 @@ // hasMany-assoc-style result: alone mode(recommendation) | ||
name: `${m.model_name}__${f}__aloneExtraWrapper`, | ||
fields: get_fields_hasmanyextra_alone(m, f, has_many_association, get_fields(rel_model.model, true)), | ||
fields: get_fields_hasmanyextra_alone(m, f, has_many_association, get_fields(assoc_model, true)), | ||
})); | ||
@@ -231,3 +235,3 @@ // hasMany-assoc-style result: mixin mode | ||
name: `${m.model_name}__${f}__mixinExtraWrapper`, | ||
fields: get_fields_hasmanyextra_mixins(m, has_many_association, get_fields(rel_model.model, true)), | ||
fields: get_fields_hasmanyextra_mixins(m, has_many_association, get_fields(assoc_model, true)), | ||
})); | ||
@@ -241,3 +245,3 @@ } | ||
}; | ||
var extend_paging_uname = get_extend_paging_unique_name(m, rel_model, f); | ||
var extend_paging_uname = get_extend_paging_unique_name(m, rel_assoc_info, f); | ||
fields[`paging_${f}`] = { | ||
@@ -244,0 +248,0 @@ type: ( |
@@ -50,65 +50,3 @@ Object.defineProperty(exports, "__esModule", { value: true }); | ||
m.no_graphql = no_graphql; | ||
m.extends = {}; | ||
var _hasOne = m.hasOne; | ||
m.hasOne = function (extend_name) { | ||
var model = arguments[1]; | ||
var orm_hasOne_opts = arguments[2]; | ||
if (arguments[1] && !arguments[1].table) { | ||
orm_hasOne_opts = arguments[1]; | ||
model = arguments[1] = null; | ||
} | ||
var assoc_model = null; | ||
m.extends[extend_name] = { | ||
type: 'hasOne', | ||
model: model, | ||
get assoc_model() { | ||
return assoc_model; | ||
}, | ||
// it's meaningless, just keep same format with `hasMany` | ||
model_associated_models: {} | ||
}; | ||
if (orm_hasOne_opts !== undefined && orm_hasOne_opts.reversed) | ||
m.extends[extend_name].reversed = true; | ||
return (assoc_model = _hasOne.apply(this, slice.call(arguments))); | ||
}; | ||
var _hasMany = m.hasMany; | ||
m.hasMany = function (extend_name, model) { | ||
var model_associated_models = {}, orm_hasMany_opts = {}; | ||
if (arguments.length >= 4) { | ||
model_associated_models = arguments[2]; | ||
orm_hasMany_opts = arguments[3]; | ||
} | ||
else { | ||
model_associated_models = {}; | ||
orm_hasMany_opts = arguments[2]; | ||
} | ||
var assoc_model = null; | ||
m.extends[extend_name] = { | ||
type: 'hasMany', | ||
model: model, | ||
get assoc_model() { | ||
return assoc_model; | ||
}, | ||
model_associated_models: model_associated_models | ||
}; | ||
if (orm_hasMany_opts && orm_hasMany_opts.reversed) | ||
m.extends[extend_name].reversed = true; | ||
return (assoc_model = _hasMany.apply(this, slice.call(arguments))); | ||
}; | ||
var _extendsTo = m.extendsTo; | ||
m.extendsTo = function (extend_name, assoc_props, orm_extendsTo_opts) { | ||
orm_extendsTo_opts = orm_extendsTo_opts || {}; | ||
orm_extendsTo_opts.hooks = orm_extendsTo_opts.hooks || {}; | ||
var assoc_model = null; | ||
m.extends[extend_name] = { | ||
type: 'extendsTo', | ||
// it's meaningless, just keep same format with `hasMany` | ||
model: null, | ||
get assoc_model() { | ||
return assoc_model; | ||
}, | ||
model_associated_models: {} | ||
}; | ||
return (assoc_model = _extendsTo.apply(this, slice.call(arguments))); | ||
}; | ||
compatSetup(m); | ||
return m; | ||
@@ -122,1 +60,66 @@ } | ||
exports.default = default_1; | ||
function compatSetup(m) { | ||
m.extends = {}; | ||
var _hasOne = m.hasOne; | ||
m.hasOne = function (extend_name) { | ||
var model = arguments[1]; | ||
var orm_hasOne_opts = arguments[2]; | ||
if (arguments[1] && !arguments[1].table) { | ||
orm_hasOne_opts = arguments[1]; | ||
model = arguments[1] = null; | ||
} | ||
var assoc_model = null; | ||
m.extends[extend_name] = { | ||
type: 'hasOne', | ||
model: model, | ||
get assoc_model() { | ||
return assoc_model; | ||
}, | ||
// it's pointless, just keep same format with `hasMany` | ||
model_associated_models: {} | ||
}; | ||
if (orm_hasOne_opts !== undefined && orm_hasOne_opts.reversed) | ||
m.extends[extend_name].reversed = true; | ||
return (assoc_model = _hasOne.apply(this, slice.call(arguments))); | ||
}; | ||
var _hasMany = m.hasMany; | ||
m.hasMany = function (extend_name, model) { | ||
var model_associated_models = {}, orm_hasMany_opts = {}; | ||
if (arguments.length >= 4) { | ||
model_associated_models = arguments[2]; | ||
orm_hasMany_opts = arguments[3]; | ||
} | ||
else { | ||
model_associated_models = {}; | ||
orm_hasMany_opts = arguments[2]; | ||
} | ||
var assoc_model = null; | ||
m.extends[extend_name] = { | ||
type: 'hasMany', | ||
model: model, | ||
get assoc_model() { | ||
return assoc_model; | ||
}, | ||
model_associated_models: model_associated_models | ||
}; | ||
if (orm_hasMany_opts && orm_hasMany_opts.reversed) | ||
m.extends[extend_name].reversed = true; | ||
return (assoc_model = _hasMany.apply(this, slice.call(arguments))); | ||
}; | ||
var _extendsTo = m.extendsTo; | ||
m.extendsTo = function (extend_name, assoc_props, orm_extendsTo_opts) { | ||
orm_extendsTo_opts = orm_extendsTo_opts || {}; | ||
orm_extendsTo_opts.hooks = orm_extendsTo_opts.hooks || {}; | ||
var assoc_model = null; | ||
m.extends[extend_name] = { | ||
type: 'extendsTo', | ||
// it's pointless, just keep same format with `hasMany` | ||
model: null, | ||
get assoc_model() { | ||
return assoc_model; | ||
}, | ||
model_associated_models: {} | ||
}; | ||
return (assoc_model = _extendsTo.apply(this, slice.call(arguments))); | ||
}; | ||
} |
@@ -8,2 +8,3 @@ Object.defineProperty(exports, "__esModule", { value: true }); | ||
type: 'text', | ||
size: 16, | ||
key: true, | ||
@@ -10,0 +11,0 @@ index: true |
@@ -183,3 +183,3 @@ /// <reference types="@fxjs/orm" /> | ||
if (act === 'read' && Array.isArray(acl)) | ||
acl = acl.concat(Object.keys(cls.extends)); | ||
acl = acl.concat(Object.keys(cls.associations)); | ||
return acl; | ||
@@ -201,4 +201,4 @@ }; | ||
if (act === 'read' && Array.isArray(acl)) | ||
acl = acl.concat(Object.keys(rcls.extends)); | ||
acl = acl.concat(Object.keys(rcls.associations)); | ||
return acl; | ||
}; |
@@ -7,3 +7,4 @@ var Viz = require('viz.js'); | ||
this.db((db) => { | ||
var m, m1; | ||
var m; | ||
// var m1: FibApp.ExtendModelWrapper; | ||
var ks; | ||
@@ -18,10 +19,10 @@ for (var name in db.models) { | ||
models.push(`${m.model_name} [tooltip="${m.model_name}", ${is_nographql ? `fillcolor="${NO_GRAPHQL_COLOR}",` : ''} label="{${m.model_name}|${ks.join('\\l')}\\l}"];`); | ||
for (var e in m.extends) { | ||
m1 = m.extends[e]; | ||
var one = m1.type === "hasOne" && !m1.reversed; | ||
var extendsTo = m1.type === "extendsTo"; | ||
for (var e in m.associations) { | ||
var assoc_info = m.associations[e]; | ||
var one = assoc_info.type === "hasOne" && !assoc_info.association.reversed; | ||
var extendsTo = assoc_info.type === "extendsTo"; | ||
if (!extendsTo) | ||
exts.push(`${m.model_name} -> ${m1.model.model_name} [label=${e} ${one ? "arrowhead=empty" : ""}];`); | ||
exts.push(`${m.model_name} -> ${assoc_info.association.model.model_name} [label=${e} ${one ? "arrowhead=empty" : ""}];`); | ||
else | ||
exts.push(`${m.model_name} -> ${m1.assoc_model.model_name} [label=${e} ${one ? "arrowhead=empty" : ""}];`); | ||
exts.push(`${m.model_name} -> ${assoc_info.association.model.model_name} [label=${e} ${one ? "arrowhead=empty" : ""}];`); | ||
} | ||
@@ -28,0 +29,0 @@ } |
@@ -49,3 +49,3 @@ Object.defineProperty(exports, "__esModule", { value: true }); | ||
} | ||
for (var k in cls.extends) { | ||
for (var k in cls.associations) { | ||
var robj = obj[k]; | ||
@@ -52,0 +52,0 @@ if (robj === undefined) |
@@ -0,23 +1,34 @@ | ||
const util = require("util"); | ||
const checkout_acl_1 = require("./checkout_acl"); | ||
const filter_1 = require("./filter"); | ||
const query_1 = require("./query"); | ||
module.exports = function (req, exec, bobj, extend) { | ||
var query = req.query; | ||
var findby = query_1.parse_findby(req); | ||
var { exists, findby_infos } = query_1.query_filter_findby(findby, exec.model, { req, pre_exec: exec }); | ||
if (findby_infos && findby_infos.length) { | ||
findby_infos.forEach(findby_info => { | ||
if (findby_info.accessor_payload && findby_info.accessor && findby_info.conditions) { | ||
exec = findby_info.accessor_payload[findby_info.accessor](findby_info.conditions); | ||
} | ||
}); | ||
} | ||
if (exists && exec.whereExists) { | ||
exec = exec.whereExists(exists); | ||
} | ||
module.exports = function (req, finder, opts) { | ||
const { extend = undefined, bmodel = null, binstance = null, } = opts || {}; | ||
const query = req.query; | ||
let exists_args = []; | ||
let init_conditions = {}; | ||
; | ||
(() => { | ||
var findby = query_1.parse_json_queryarg(req, 'findby'); | ||
var { exists: findby_exists, findby_infos } = query_1.query_filter_findby(findby, bmodel, { req }); | ||
if (findby_infos && findby_infos.length) { | ||
findby_infos.forEach(findby_info => { | ||
if (findby_info.accessor_payload && findby_info.accessor && findby_info.conditions) { | ||
finder = findby_info.accessor_payload[findby_info.accessor]; | ||
init_conditions = util.extend(init_conditions, findby_info.conditions); | ||
} | ||
}); | ||
} | ||
if (Array.isArray(findby_exists)) | ||
exists_args = exists_args.concat(findby_exists); | ||
})(); | ||
const join_where = query_1.query_filter_join_where(req); | ||
let exec = finder(init_conditions, { join_where }); | ||
if (exists_args.length && exec.whereExists) | ||
exec = exec.whereExists(exists_args); | ||
var keys = query.keys; | ||
if (keys !== undefined) | ||
exec = exec.only(keys); | ||
var where = query_1.query_filter_where(query); | ||
exec = exec.where(where); | ||
var where = query_1.query_filter_where(req); | ||
exec = exec.where(where, { join_where }); | ||
var skip = query_1.query_filter_skip(query); | ||
@@ -27,9 +38,5 @@ exec = exec.offset(skip); | ||
exec = exec.limit(limit); | ||
var order = query.order; | ||
if (order !== undefined) { | ||
order = order || ''; | ||
const order_list = order.split(',').filter(x => x); | ||
order_list.forEach(order => exec = exec.order(order)); | ||
} | ||
// avoid extra find action such as `exec.allSync()` | ||
query_1.query_filter_order(query) | ||
.map(order => exec = exec.order(order)); | ||
// avoid unnecessary find action such as `exec.allSync()` | ||
var objs = []; | ||
@@ -40,5 +47,5 @@ if (limit > 0) { | ||
objs = objs.map(obj => { | ||
var a; | ||
let a; | ||
if (extend !== undefined) | ||
a = checkout_acl_1.checkout_robj_acl(req.session, 'read', bobj, obj, extend); | ||
a = checkout_acl_1.checkout_robj_acl(req.session, 'read', binstance, obj, extend); | ||
else | ||
@@ -45,0 +52,0 @@ a = checkout_acl_1.checkout_obj_acl(req.session, 'read', obj); |
/// <reference path="../../@types/index.d.ts" /> | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const util = require("util"); | ||
const ORM = require("@fxjs/orm"); | ||
const Helpers = ORM.Helpers; | ||
const err_info_1 = require("../utils/err_info"); | ||
const checkout_acl_1 = require("./checkout_acl"); | ||
const orm_assoc_1 = require("./orm-assoc"); | ||
exports._get = function (cls, id, session, act) { | ||
@@ -36,4 +37,4 @@ var iobj = { | ||
exports._egetx = function (cls, id, extend, rid, session, act) { | ||
var rel_model = cls.extends[extend]; | ||
if (rel_model === undefined) | ||
var rel_assoc_info = cls.associations[extend]; | ||
if (rel_assoc_info === undefined) | ||
return wrap_error(err_info_1.err_info(4040001, { | ||
@@ -61,6 +62,8 @@ classname: extend | ||
} | ||
var __opt, is_extendsTo = rel_model.type === 'extendsTo', key_model = is_extendsTo ? rel_model.assoc_model : rel_model.model, assoc = orm_assoc_1.get_association_item_by_reltype(rel_model.type, iobj.inst, extend); | ||
switch (rel_model.type) { | ||
var __opt, is_extendsTo = rel_assoc_info.type === 'extendsTo', | ||
// key_model = is_extendsTo ? rel_assoc_info.assoc_model : rel_assoc_info.model, | ||
rel_type = rel_assoc_info.type, key_model = rel_assoc_info.association.model, assoc = Helpers.getAssociationItemFromInstanceByExtname(rel_assoc_info.type, iobj.inst, extend); | ||
switch (rel_type) { | ||
default: | ||
throw `invalid rel_model.type ${rel_model.type}`; | ||
throw `invalid rel_assoc_info.type ${rel_type}`; | ||
case 'extendsTo': | ||
@@ -71,3 +74,3 @@ __opt = assoc.model.find({}); | ||
case 'hasOne': | ||
if (rel_model.reversed) | ||
if (rel_assoc_info.association.reversed) | ||
__opt = iobj.inst[assoc.getAccessor].call(iobj.inst); | ||
@@ -82,4 +85,4 @@ else { | ||
classname: `${cls.model_name}.${extend}` | ||
}, rel_model.model.cid)); | ||
__opt = rel_model.model.find(); | ||
}, rel_assoc_info.association.model.cid)); | ||
__opt = rel_assoc_info.association.model.find(); | ||
} | ||
@@ -86,0 +89,0 @@ break; |
Object.defineProperty(exports, "__esModule", { value: true }); | ||
/// <reference types="@fxjs/orm" /> | ||
const util = require("util"); | ||
function get_many_associations(instance) { | ||
return instance.__opts.many_associations; | ||
} | ||
exports.get_many_associations = get_many_associations; | ||
function get_many_association_item(instance, extend_name) { | ||
const many_assocs = get_many_associations(instance); | ||
return many_assocs.find(a => a.name === extend_name); | ||
} | ||
exports.get_many_association_item = get_many_association_item; | ||
function get_one_associations(instance) { | ||
return instance.__opts.one_associations; | ||
} | ||
exports.get_one_associations = get_one_associations; | ||
function get_one_association_item(instance, extend_name) { | ||
const one_assocs = get_one_associations(instance); | ||
return one_assocs.find(a => a.name === extend_name); | ||
} | ||
exports.get_one_association_item = get_one_association_item; | ||
function get_extendsto_associations(instance) { | ||
return instance.__opts.extend_associations; | ||
} | ||
exports.get_extendsto_associations = get_extendsto_associations; | ||
function get_extendsto_association_item(instance, extend_name) { | ||
const extendsto_assocs = get_extendsto_associations(instance); | ||
return extendsto_assocs.find(a => a.name === extend_name); | ||
} | ||
exports.get_extendsto_association_item = get_extendsto_association_item; | ||
function get_association_item_by_reltype(reltype, inst, extend) { | ||
switch (reltype) { | ||
default: | ||
throw 'invalid association reltype!'; | ||
case 'extendsTo': | ||
return get_extendsto_association_item(inst, extend); | ||
case 'hasOne': | ||
return get_one_association_item(inst, extend); | ||
case 'hasMany': | ||
return get_many_association_item(inst, extend); | ||
} | ||
} | ||
exports.get_association_item_by_reltype = get_association_item_by_reltype; | ||
function check_hasmany_extend_extraprops(instance, extend_name) { | ||
function check_hasmanyassoc_with_extraprops(instance, extend_name) { | ||
var has_many_association = instance.__opts.many_associations.find(a => a.name === extend_name); | ||
@@ -49,3 +9,3 @@ var has_extra_fields = has_many_association && has_many_association.props && util.isObject(has_many_association.props) && Object.keys(has_many_association.props).length; | ||
} | ||
exports.check_hasmany_extend_extraprops = check_hasmany_extend_extraprops; | ||
exports.check_hasmanyassoc_with_extraprops = check_hasmanyassoc_with_extraprops; | ||
function extra_save(instance, rinstance, _many_assoc, extra, just_set = false) { | ||
@@ -52,0 +12,0 @@ if (Array.isArray(extra)) |
/// <reference lib="es2017" /> | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const orm = require("@fxjs/orm"); | ||
const util = require("util"); | ||
const orm_assoc_1 = require("./orm-assoc"); | ||
const ORM = require("@fxjs/orm"); | ||
const Helpers = ORM.Helpers; | ||
const checkout_acl_1 = require("./checkout_acl"); | ||
const str_1 = require("./str"); | ||
function query_filter_where(query) { | ||
var where = query.where; | ||
if (where !== undefined) | ||
where = convert_where(where); | ||
else | ||
where = {}; | ||
function query_filter_where(req) { | ||
var where = parse_json_queryarg(req, 'where'); | ||
where = where || {}; | ||
return where; | ||
} | ||
exports.query_filter_where = query_filter_where; | ||
function query_filter_findby(findby, base_model, opts) { | ||
const { req, pre_exec = null } = opts; | ||
function query_filter_join_where(req) { | ||
var join_where = parse_json_queryarg(req, 'join_where'); | ||
join_where = join_where || {}; | ||
return join_where; | ||
} | ||
exports.query_filter_join_where = query_filter_join_where; | ||
function query_filter_findby(findby, exec_model, opts) { | ||
const { req } = opts; | ||
const __wrapper = { exists: null, findby_infos: [] }; | ||
@@ -24,56 +27,59 @@ if (!findby) | ||
return __wrapper; | ||
let hasmany_assoc; | ||
let found_assoc; | ||
const base_instance = new base_model(); | ||
if (findby.on | ||
&& (found_assoc = hasmany_assoc = orm_assoc_1.get_many_association_item(base_instance, findby.extend))) { | ||
// TODO: make sure order of mg_ks is corresponding to mks | ||
const mg_ks = Object.values(hasmany_assoc.mergeId).map(x => x.mapsTo); | ||
const mks = base_model.id; | ||
if (!checkout_acl_1.checkout_acl(req.session, 'find', base_model.ACL, findby.extend)) | ||
return __wrapper; | ||
/** | ||
* @description code below means 'support single key only' | ||
*/ | ||
// const mg_assocks = Object.values(hasmany_assoc.mergeAssocId).map(x => x.mapsTo); | ||
// if (mg_assocks.length !== 1 || mks.length !== 1) return __wrapper; | ||
__wrapper.exists = [ | ||
{ | ||
table: hasmany_assoc.mergeTable, | ||
link: [mg_ks, mks], | ||
conditions: findby.on | ||
} | ||
]; | ||
__wrapper.exists = convert_exists(__wrapper.exists); | ||
} | ||
else if (findby.where | ||
&& ((found_assoc = orm_assoc_1.get_one_association_item(base_instance, findby.extend)) | ||
|| | ||
(found_assoc = orm_assoc_1.get_extendsto_association_item(base_instance, findby.extend)))) { | ||
let findby_conditions = findby.where; | ||
if (!filter_conditions(findby_conditions)) | ||
return __wrapper; | ||
findby_conditions = convert_where(findby_conditions); | ||
if (!checkout_acl_1.checkout_acl(req.session, 'find', base_model.ACL, findby.extend)) | ||
return __wrapper; | ||
let accessor_fn = null, accessor_name = null, accessor_payload = null; | ||
const findby_accessor_name = found_assoc.modelFindByAccessor || `findBy${str_1.ucfirst(findby.extend)}`; | ||
; | ||
[ | ||
base_model | ||
].forEach(test_payload => { | ||
if (accessor_name) | ||
const exec_instance = new exec_model(); | ||
(() => { | ||
if (findby.on | ||
&& (found_assoc = Helpers.getManyAssociationItemFromInstanceByExtname(exec_instance, findby.extend))) { | ||
const hasmany_assoc = found_assoc; | ||
// TODO: make sure order of mg_ks is corresponding to mks | ||
const mg_ks = Object.values(hasmany_assoc.mergeId).map(x => x.mapsTo); | ||
const mks = exec_model.id; | ||
if (!checkout_acl_1.checkout_acl(req.session, 'find', exec_model.ACL, findby.extend)) | ||
return; | ||
accessor_fn = test_payload[findby_accessor_name]; | ||
if (typeof accessor_fn === 'function') { | ||
accessor_payload = test_payload; | ||
accessor_name = findby_accessor_name; | ||
} | ||
}); | ||
__wrapper.findby_infos.push({ | ||
accessor: accessor_name, | ||
accessor_payload: accessor_payload, | ||
conditions: findby_conditions | ||
}); | ||
} | ||
/** | ||
* @description code below means 'support single key only' | ||
*/ | ||
const exists_conditions = findby.on; | ||
if (!filter_conditions(exists_conditions)) | ||
return; | ||
__wrapper.exists = [ | ||
{ | ||
table: hasmany_assoc.mergeTable, | ||
link: [mg_ks, mks], | ||
conditions: exists_conditions | ||
} | ||
]; | ||
__wrapper.exists = convert_exists(__wrapper.exists); | ||
} | ||
})(); | ||
; | ||
(() => { | ||
if (findby.where | ||
&& ((found_assoc = Helpers.getAssociationItemFromInstanceByExtname('hasOne', exec_instance, findby.extend)) | ||
|| (found_assoc = Helpers.getAssociationItemFromInstanceByExtname('hasMany', exec_instance, findby.extend)) | ||
|| (found_assoc = Helpers.getAssociationItemFromInstanceByExtname('extendsTo', exec_instance, findby.extend)))) { | ||
const findby_conditions = findby.where; | ||
if (!filter_conditions(findby_conditions)) | ||
return; | ||
if (!checkout_acl_1.checkout_acl(req.session, 'find', exec_model.ACL, findby.extend)) | ||
return; | ||
let accessor_fn = null, accessor_name = null, accessor_payload = null; | ||
const findby_accessor_name = found_assoc.modelFindByAccessor || `findBy${str_1.ucfirst(findby.extend)}`; | ||
; | ||
[exec_model].forEach(test_payload => { | ||
if (accessor_name) | ||
return; | ||
accessor_fn = test_payload[findby_accessor_name]; | ||
if (typeof accessor_fn === 'function') { | ||
accessor_payload = test_payload; | ||
accessor_name = findby_accessor_name; | ||
} | ||
}); | ||
__wrapper.findby_infos.push({ | ||
accessor: accessor_name, | ||
accessor_payload: accessor_payload, | ||
conditions: findby_conditions | ||
}); | ||
} | ||
})(); | ||
return __wrapper; | ||
@@ -96,2 +102,12 @@ } | ||
exports.query_filter_limit = query_filter_limit; | ||
function query_filter_order(query) { | ||
let order_list = []; | ||
var order = query.order; | ||
if (order !== undefined) { | ||
order = order || ''; | ||
order_list = order.split(',').filter(x => x); | ||
} | ||
return order_list; | ||
} | ||
exports.query_filter_order = query_filter_order; | ||
function is_count_required(query) { | ||
@@ -107,60 +123,3 @@ if (!query) | ||
exports.found_result_selector = found_result_selector; | ||
const model_conjunctions_keys = [ | ||
'or', | ||
'and', | ||
'not_or', | ||
'not_and', | ||
'not' | ||
]; | ||
const ops = { | ||
"like": orm.like, | ||
"eq": orm.eq, | ||
"ne": orm.ne, | ||
"gt": orm.gt, | ||
"gte": orm.gte, | ||
"lt": orm.lt, | ||
"lte": orm.lte, | ||
"not_like": orm.not_like, | ||
"not_in": orm.not_in | ||
}; | ||
function convert_where(where, result_where = {}) { | ||
var conjunction_where = util.pick(where, model_conjunctions_keys); | ||
var normal_where = util.omit(where, model_conjunctions_keys); | ||
for (let k in conjunction_where) { | ||
const cw = conjunction_where[k]; | ||
if (!Array.isArray(cw)) | ||
continue; | ||
result_where[k] = cw.map((o) => convert_where(o)); | ||
} | ||
for (var k in normal_where) { | ||
var v = normal_where[k]; | ||
if (util.isArray(v)) | ||
result_where[k] = v; | ||
else if (util.isObject(v)) { | ||
const keys = Object.keys(v); | ||
if (keys.length >= 1) { | ||
var op = keys[0]; | ||
if (op === "between") { | ||
var as = v[op]; | ||
if (util.isArray(as)) | ||
result_where[k] = orm.between(as[0], as[1]); | ||
} | ||
else if (op === "not_between") { | ||
var as = v[op]; | ||
if (util.isArray(as)) | ||
result_where[k] = orm.not_between(as[0], as[1]); | ||
} | ||
else if (op === "in") | ||
result_where[k] = v[op]; | ||
else if (ops[op]) | ||
result_where[k] = ops[op](v[op]); | ||
} | ||
} | ||
else | ||
result_where[k] = v; | ||
} | ||
return result_where; | ||
} | ||
; | ||
function convert_exists(exists) { | ||
function convert_exists(exists, is_allow_empty_link = false) { | ||
if (!Array.isArray(exists)) | ||
@@ -173,9 +132,9 @@ exists = []; | ||
return false; | ||
if (!filter_exist_item_link(exist_item)) | ||
return false; | ||
if (!filter_exist_item_link(exist_item)) { | ||
if (!is_allow_empty_link) | ||
return false; | ||
exist_item.link = [[], []]; | ||
} | ||
if (!filter_conditions(exist_item.conditions)) | ||
return false; | ||
exist_item.conditions = convert_where(exist_item.conditions); | ||
if (!filter_conditions(exist_item.conditions)) | ||
return false; | ||
return true; | ||
@@ -185,16 +144,15 @@ }); | ||
; | ||
function parse_findby(req) { | ||
const query = req.query; | ||
var findby = (query.findby || null); | ||
if (typeof findby === 'string') { | ||
function parse_json_queryarg(req, k) { | ||
var parsed = (req.query[k] || null); | ||
if (typeof parsed === 'string') { | ||
try { | ||
findby = JSON.parse(findby); | ||
parsed = JSON.parse(parsed); | ||
} | ||
catch (e) { | ||
findby = null; | ||
parsed = null; | ||
} | ||
} | ||
return findby; | ||
return parsed; | ||
} | ||
exports.parse_findby = parse_findby; | ||
exports.parse_json_queryarg = parse_json_queryarg; | ||
// internal helper function for `filter_exist_item_link` | ||
@@ -214,4 +172,4 @@ function filter_link_tuple(tuple) { | ||
/** | ||
* tuple1: ['t1_assocf', 't2_assocf'] | ||
* tuple2: [ | ||
* exist_item.link: ['t1_assocf', 't2_assocf'] | ||
* exist_item.link: [ | ||
* ['t1_assocf1', 't1_assocf2'], | ||
@@ -253,1 +211,6 @@ * ['t2_assocf1', 't2_assocf2'], | ||
} | ||
function find_date_property_keys_from_property_hash(hash) { | ||
return Object.keys(hash).filter(pname => { | ||
return hash[pname].type === 'date'; | ||
}); | ||
} |
{ | ||
"name": "fib-app", | ||
"version": "1.13.24", | ||
"version": "1.13.25", | ||
"description": "", | ||
@@ -24,3 +24,3 @@ "main": "./lib", | ||
"dependencies": { | ||
"@fxjs/orm": "^1.8.7", | ||
"@fxjs/orm": "^1.9.2", | ||
"@types/fibjs": "^0.26.5", | ||
@@ -35,3 +35,3 @@ "fib-graphql": "^1.0.0", | ||
"devDependencies": { | ||
"@fibjs/ci": "^2.1.0", | ||
"@fibjs/ci": "^2.2.0", | ||
"@fibjs/detect-port": "^1.0.1", | ||
@@ -42,7 +42,7 @@ "cheerio": "^1.0.0-rc.2", | ||
"fib-pug": "0.0.2", | ||
"fib-push": "^1.3.0", | ||
"fib-typify": "^0.5.1" | ||
"fib-push": "^1.4.1", | ||
"fib-typify": "^0.5.2" | ||
}, | ||
"peerDependencies": { | ||
"@fxjs/orm": ">= 1.8.7 < 2" | ||
"@fxjs/orm": ">= 1.9.2 < 2" | ||
}, | ||
@@ -59,4 +59,7 @@ "ci": { | ||
"0.26.1" | ||
], | ||
"travis_services": [ | ||
"mysql" | ||
] | ||
} | ||
} |
117
README.md
@@ -365,3 +365,3 @@ # fib-app | ||
**Started From 1.13.20** | ||
**Started From 1.13.20, >= 1.13.25 Recommended** | ||
@@ -371,5 +371,5 @@ 通过 `findby` 参数的形式可以对查询对象做出约束。和 `where` 一样, `findby` 参数的值应该是被 JSON 编码又经过 url 编码的的。 | ||
参数包含的选项含义如下 | ||
- `findby.extend` 是由 orm 定义时的 `hasOne`, `hasMany` 关联关系. 如 extend 描述的**关联关系**对该**基础对象**而言不存在, 则该 `findby` 条件实际上不会生效. | ||
- `findby.where`: 只适用于 `hasOne` 关系. 与[基础的 where](#where-选项) 含义一致. | ||
- `findby.on`: 只适用于 `hasMany` 关系. 与[基础的 where](#where-选项) 含义一致, 但其 key 只能是关联关系中的字段, 而不能是被关联中的对象中的字段. | ||
- `findby.extend` 是由 orm 定义时的 `hasOne`, `hasMany`, `extendsTo` 关联关系. 如 extend 描述的**关联关系**对该**基础对象**而言不存在, 则该 `findby` 条件实际上不会生效. | ||
- `findby.where`: <del>只适用于 `hasOne` 关系</del> 适用于所有的扩展关系. 与[基础的 where](#where-选项) 含义一致. | ||
- `findby.on`: 只适用于 `hasMany` 关系. 与[基础的 where](#where-选项) 含义一致, 但其 key 只能是关联关系中的字段, 而不能是被关联中的对象中的字段. 推荐使用功能更为完备的 `findby.where` | ||
@@ -402,2 +402,111 @@ 例如, 存在以下关系 | ||
#### join_where 过滤条件 | ||
**Started From 1.13.25** | ||
通过 `join_where` 参数的形式可以在对具有 hasMany 关系的扩展对象查询时, 对关联表中的字段进行筛选做出约束。和 `where` 一样, `join_where` 参数的值应该是被 JSON 编码又经过 url 编码的的。 | ||
例如, 存在以下关系 | ||
- person hasMany pets, 且含有扩展字段: | ||
- nickname: { type: "text", size: 256 } | ||
现在我们希望查询级联的用户、宠物信息, 要求**按照"拥有年龄不低于 1 岁的的宠物" 对 person 进行 findby 查找** | ||
一般可以使用 graphql 进行查询, 如下: | ||
```graphql | ||
# curl -X POST http://localhost/graphql -H 'content-type: application/graphql' | ||
{ | ||
find_persons( | ||
findby: { | ||
# 按拥有"年龄不低于 1 岁的宠物"为条件找到用户 | ||
extend: "pets" | ||
where: { | ||
age: { gt: 1 } | ||
} | ||
} | ||
){ | ||
id | ||
name | ||
pets{ | ||
id | ||
name | ||
extra{ | ||
nickname | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
如果我们希望在做 pets 查询时, 过滤出其宠物 nickname 含有 `a` 字母的宠物, 则可以这样写: | ||
```graphql | ||
# curl -X POST http://localhost/graphql -H 'content-type: application/graphql' | ||
{ | ||
find_persons( | ||
findby: { | ||
# 按拥有"年龄不低于 1 岁的宠物"为条件找到用户 | ||
extend: "pets" | ||
where: { | ||
age: { gte: 1 } | ||
} | ||
} | ||
){ | ||
id | ||
name | ||
pets( | ||
join_where: { | ||
nickname: { like: "%a%" } | ||
} | ||
){ | ||
id | ||
name | ||
extra{ | ||
nickname | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
**注意** 由于 M:N 类型的数据标关系固有特点, 由 `findby` 筛选出的用户**必然**拥有一岁以上的宠物, 但并**不一定只**拥有一岁以上的宠物. 如果你希望读取 pets 时只筛选出年龄不低于 1 岁的宠物, 记得使用 where 对 pets 也进行过滤, 如下: | ||
```graphql | ||
# curl -X POST http://localhost/graphql -H 'content-type: application/graphql' | ||
{ | ||
find_persons( | ||
findby: { | ||
# 按拥有"年龄不低于 1 岁的宠物"为条件找到用户 | ||
extend: "pets" | ||
where: { | ||
age: { gte: 1 } | ||
} | ||
} | ||
){ | ||
id | ||
name | ||
pets( | ||
where: { | ||
age: {gte: 1} | ||
} | ||
# where 和 join_where 可以一起使用, 二者含义不同 | ||
# where 的筛选对象是 pet 本身的字段; | ||
# join_where 的筛选对象是 person-pet 关系中的扩展字段; | ||
join_where: { | ||
nickname: { like: "%a%" } | ||
} | ||
){ | ||
id | ||
name | ||
extra{ | ||
nickname | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
## ACL | ||
@@ -404,0 +513,0 @@ 可以通过定义 Model 的 ACL 控制数据权限。比如: |
Sorry, the diff of this file is not supported yet
775
169458
50
3276
Updated@fxjs/orm@^1.9.2