think.model 提供了丰富的CRUD方法,下面说明一下这些组合方法转为 sql 的实现原理
以 select 为例
const userData = await this.model(‘user‘).where({ token, phone}).find();
think-model model.js 部分代码; where、find 方法会处理options 然后返回 this 供下一个方法继续使用,其他方法同理
/** * set where options * @return {} [] */ where(where) { if (!where) return this; if (helper.isString(where)) { where = { _string: where }; } const options = this.options; if (options.where && helper.isString(options.where)) { options.where = { _string: options.where }; // 给 options 加上 where 属性 } options.where = helper.extend({}, options.where, where); return this; } /** * find data * @return Promise */ find(options) { var _this8 = this; return _asyncToGenerator(function* () { options = yield _this8.parseOptions(options); // 最后处理options
options.limit = 1; options = yield _this8.beforeFind(options); const data = yield _this8.db().select(options); // 调用 think-model-abstract selece() return _this8.afterFind(data[0] || {}, options); })(); } /** * before find */ beforeFind(options) { return options; } /** * after find * @return {} [] */ afterFind(data) { return this[RELATION].afterFind(data); } /** * parse options, reset this.options to {} * @param {Object} options */ parseOptions(options) { var _this = this; return _asyncToGenerator(function* () { if (helper.isNumber(options) || helper.isString(options)) { options += ‘‘; const where = { [_this.pk]: options.indexOf(‘,‘) > -1 ? { IN: options } : options }; options = { where }; } options = helper.extend({}, _this.options, options); _this.options = {}; options.table = options.table || _this.tableName; options.tablePrefix = _this.tablePrefix; options.pk = _this.pk; // add primary key for options
if (options.field && options.fieldReverse) { options.field = yield _this.db().getReverseFields(options.field); delete options.fieldReverse; } return options; })(); }
上方处理完 options 调用 select() 方法。。。
think-model-abstract query.js 部分代码
/** * select * @param {Object} options [] * @return {Promise} [] */ select(options, cache) { const parser = this.parser; let sql; if (helper.isObject(options)) { sql = options.sql ? options.sql : parser.buildSelectSql(options); // options 是否已有sql,没有先拼接 sql,具体代码在下方 cache = cache || options.cache; } else { sql = options; } if (!cache) return this.query(sql); cache.key = cache.key || helper.md5(sql); const Handle = cache.handle; const instance = new Handle(cache); return instance.get(cache.key).then(data => { if (data !== undefined) { debug(`get data from cache: ${JSON.stringify(cache)}`); return data; } return this.query(sql).then(data => { return instance.set(cache.key, data).then(() => { return data; }); }); }); }
生成 sql 代码:
think-model-abstract parse.js 部分代码
/** * get select sql * @param {Object} options [] * @return {String} [sql string] */ buildSelectSql(options) { // 这是 select sql的完整模板
const sql = ‘%EXPLAIN%SELECT%DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT%%UNION%%LOCK%%COMMENT%‘; return this.parseSql(sql, options); } /** * parse sql * @param {String} sql [] * @param {Object} options [] * @return {String} [] */ parseSql(sql, options) { // 把模板中需要填充的位置(%。。。%)用 options 的数据转为相应 sql ;
return sql.replace(/%([A-Z]+)%/g, (a, type) => { // 以模板填充位置 WHERE 为例;
type = type.toLowerCase(); // type = "where";
const ucfirst = type[0].toUpperCase() + type.slice(1); // ucfirst = "Where"
if (helper.isFunction(this[‘parse‘ + ucfirst])) { // 此处存在 parseWhere 函数 return this[‘parse‘ + ucfirst](options[type] || ‘‘, options); // 把 where 属性转为 sql } return a; }).replace(/\s__([A-Z_-]+)__\s?/g, (a, b) => { return ‘ `‘ + this.config.prefix + b.toLowerCase() + ‘` ‘; }); } /** * parse where * @param {Mixed} where [] * @return {String} [] */ parseWhere(where) { if (helper.isEmpty(where)) { return ‘‘; } else if (helper.isString(where)) { return ` WHERE ${where}`; } const logic = this.getLogic(where); // safe key regexp
const keySafeRegExp = /^[\w|&\-.(),]+$/; const multi = where._multi; delete where._multi; // eslint-disable-next-line one-var
let key, val, result = [], str = ‘‘; const fn = (item, i) => { const v = multi ? val[i] : val; return ‘(‘ + this.parseWhereItem(this.parseKey(item), v) + ‘)‘; }; for (key in where) { val = where[key]; str = ‘( ‘; // _string: ‘‘
if ([‘_string‘, ‘_complex‘, ‘_query‘].indexOf(key) > -1) { str += this.parseThinkWhere(key, val); } else if (!keySafeRegExp.test(key)) { throw new Error(‘INVALID_WHERE_CONDITION_KEY‘); // title|content
} else if (key.indexOf(‘|‘) > -1) { str += key.split(‘|‘).map(fn).join(‘ OR ‘); // title&content
} else if (key.indexOf(‘&‘) > -1) { str += key.split(‘&‘).map(fn).join(‘ AND ‘); } else { str += this.parseWhereItem(this.parseKey(key), val); } str += ‘ )‘; result.push(str); } result = result.join(` ${logic} `); return result ? ` WHERE ${result}` : ‘‘; }
至此 就是查询数据的完整逻辑,欢迎大佬指正;