UNPKG

zing-orm

Version:
397 lines 28.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ArangodbRepository = void 0; // const _ = require('lodash'); const moment = require("moment"); const arangojs_1 = require("arangojs"); const RepositoryParams_1 = require("../types/RepositoryParams"); const JoiUtils_1 = require("../../util/JoiUtils"); // import { CommonTools } from '../../util/CommonTools'; const globals_1 = require("../../util/globals"); /** * Entity manager supposed to work with any entity, automatically find its repository and call its methods, * whatever entity type are you passing. */ class ArangodbRepository { // ------------------------------------------------------------------------- // Constructor // ------------------------------------------------------------------------- constructor(_connection, _entity) { // 过滤属性,在非赋值情况不覆盖数据:update,insert this.unset = ['_id', '_rev', '_key', '_status', '_create_date']; // super(async () => { try { if (!_entity) { throw Error(`constructor params::_entity can not be ${JSON.stringify(_entity)} !!!`); } this.connection = _connection; // this.queryBuilder = knex({ client: 'mssql' }); this.entity = _entity; this.tableName = (0, globals_1.findTableName)(_entity); } catch (err) { //todo console.error("初始化 ArangodbRepository Class 失败!!!", err); } // }) } // ------------------------------------------------------------------------- // Public Methods // ------------------------------------------------------------------------- async executeSql(params) { try { await JoiUtils_1.JoiUtils.checkParams(RepositoryParams_1.ExecuteSqlParamsSchema, params); return await ArangodbRepository.executeSqlRaw(this.connection, params); } catch (err) { console.log("executeSql error:", err); throw Error(`executeSql failed!!!, error: ${err}`); } } static async executeSqlRaw(connection, params) { await JoiUtils_1.JoiUtils.checkParams(RepositoryParams_1.ExecuteSqlParamsSchema, params); var { sql, binds = {}, options = {} } = params; console.log("executeSqlRaw params: ", sql, binds, options); const cursor = await await connection.query({ query: sql, bindVars: binds }); let result = await cursor.all(); console.log("executeSqlRaw Query results: "); console.dir(result); return result; } // ------------------------------------------------------------------------- // Protected Methods // ------------------------------------------------------------------------- /** * 处理数组属性的查询参数 * @param {string} alias 别名 * @param {string} key 属性名 * @param {any} data 数据值 */ getArrayAttrAql(alias, key, data) { const arrayAttrAqlList = []; // 数组拆分元素用 or 连接 if (Array.isArray(data)) { // 处理 or 条件 data && data.forEach((el, idx) => { if (idx === 0) { arrayAttrAqlList.push((0, arangojs_1.aql) `\nFILTER `); } // filter 隐含了 ‘and’条件,所以只需要所有的 ‘or’ 条件连接在一个 filter 即可 if (idx === data.length - 1) { arrayAttrAqlList.push((0, arangojs_1.aql) `${el} in ${alias}.${key} `); } else { arrayAttrAqlList.push((0, arangojs_1.aql) `${el} in ${alias}.${key} or `); } }); } else { arrayAttrAqlList.push((0, arangojs_1.aql) `\nFILTER ${data} in ${alias}.${key}`); } return arangojs_1.aql.join(arrayAttrAqlList); } /** * 拼装过滤参数:使用FILTER可以利用索引(and连接) * - (单数类型)默认==匹配 * - array类型使用in匹配 * - object{opr, value}类型使用指定操作符 * - opr = 'POSITION' 时需要处理数组属性的查询参数 * aql.join, aql.literal @see https://www.arangodb.com/docs/devel/appendix-java-script-modules-arango-db.html * @param {object} filter 查询参数对象 * @param {string} alias alias of collection * @return {AQL} obj */ getFilterAql(filter, alias) { // 默认别名为't' if (!alias) { alias = 't'; } alias = arangojs_1.aql.literal(alias); let filterAql; if (filter) { let filterAqlList = []; const otherFilterAqlList = []; const arrayAttrAqlList = []; let first = true; for (const key in filter) { const data = filter[key]; if (data !== undefined) { if (Array.isArray(data)) { // 数组参数,则‘in’ filterAqlList.push((0, arangojs_1.aql) ` and ${alias}.${key} in ${data}`); } else if (!!data && typeof data === 'object') { /** * 对象参数结构{opr, value} * 支持:==, !=, <, <=, >, >=, IN, NOT IN, LIKE, =~, !~ * 注意: typeof null === 'object' * 增加:opr = 'POSITION' 时需要处理数组属性的查询参数 */ if (data.opr === 'POSITION') { arrayAttrAqlList.push(this.getArrayAttrAql(alias, key, data.value)); } else { otherFilterAqlList.push((0, arangojs_1.aql) ` and ${alias}.${key} ${arangojs_1.aql.literal(data.opr)} ${data.value}`); } } else { // 单个参数,默认‘==’ filterAqlList.push((0, arangojs_1.aql) ` and ${alias}.${key} == ${data}`); } if (first) first = false; } } // otherFilterAqlList在后,符合最左匹配原则 filterAqlList = filterAqlList.concat(otherFilterAqlList).concat(arrayAttrAqlList); if (filterAqlList.length !== 0) { filterAql = arangojs_1.aql.join(filterAqlList); } } return filterAql; } /** * 处理排序字符串(不含SORT) * @param {object} sorts params * @param {string} alias alias of collection * @return {AQL} obj */ getSortFieldAqlList(sorts, alias) { // 默认别名为't' if (!alias) { alias = 't'; } alias = arangojs_1.aql.literal(alias); // 默认时间倒序和_id倒序 const fieldAqlList = [(0, arangojs_1.aql) ` ${alias}._create_date desc, ${alias}._id desc `]; // const fieldAqlList = [aql` ${alias}._id `]; if (sorts) { // 删除默认排序 fieldAqlList.shift(); sorts && sorts.forEach((el) => { if (!el.direction) { fieldAqlList.push((0, arangojs_1.aql) `${alias}.${el.field}`); } else { fieldAqlList.push((0, arangojs_1.aql) `${alias}.${el.field} ${el.direction}`); } }); } return fieldAqlList; } /** * 拼装排序条件 * @param {array} sortFieldAqlList params * @return {AQL} obj */ getSortAql(sortFieldAqlList) { if (sortFieldAqlList && sortFieldAqlList.length > 0) { // 添加到开头 const sorts = [(0, arangojs_1.aql) ` SORT`]; sorts.push(sortFieldAqlList[0]); // 补逗号 for (let i = 1; i < sortFieldAqlList.length; i++) { sorts.push((0, arangojs_1.aql) `, `); sorts.push(sortFieldAqlList[i]); } sortFieldAqlList = sorts; } // 拼接完整sort AQL return arangojs_1.aql.join(sortFieldAqlList); } /** * Find with pagination and condition. * - cant use findAndCount for both params * - use createQueryBuilder * @param params 参数 * @param params.current 页码 * @param params.pageSize 页面条数 * @param params.sort 排序 * @param dataFunc 数据处理函数 */ //todo add filter, knex async getPage(params) { try { await JoiUtils_1.JoiUtils.checkParams(RepositoryParams_1.GetPageParamsSchema, params); let { current, pageSize, sorts, filter // options } = params; // 转换分页参数:pageNum,page_size => offset,count let offset = (current - 1) * pageSize; let count = pageSize; const collection = arangojs_1.aql.literal(`${this.tableName}`); const filterAql = this.getFilterAql(filter); // 拼装排序条件 默认创建时间倒序 const sortAql = this.getSortAql(this.getSortFieldAqlList(sorts)); // const collections = this.aql.literal(`${pluralize(this.getLowerCollectionName())}`); const query = (0, arangojs_1.aql) ` LET ts = ( FOR t IN ${collection} FILTER t._status == true ${filterAql} ${sortAql} RETURN t ) LET tsl = ( LET list = ( FOR tl IN ts LIMIT ${offset},${count} RETURN tl ) RETURN list ) LET total = LENGTH(ts) LET flag = (${offset} + ${count} >= total) LET hasMore = !flag RETURN {total:total, hasMore:hasMore, list:tsl[0]}`; const rows = await this.executeSql({ sql: query.query, binds: query.bindVars }); let result = Object.assign({}, rows[0], { totalPage: Math.ceil(rows[0].total / pageSize), current, pageSize, }); return result; } catch (err) { console.error("ArangodbRepository getPage 失败!!!", err); throw Error(`ArangodbRepository getPage 失败!!!, 错误: ${err}`); } } /** * get documents by filter of collection * @param {object} _params - params object * @param {object} _params.filter - filter of attrs. * @param {object} _params.like - the object to like the documents to get from the collection * @param {array} _params.sorts - array of sort str for attrs. * @param {object} _params.options - query options, e.g. keepAttrs-res attrs; hasEdge-edge res; * @return {AqlQuery} - interface AqlQuery by arangodb */ async getsByFilter(params) { try { await JoiUtils_1.JoiUtils.checkParams(RepositoryParams_1.GetsByFilterParamsSchema, params); let { filter, sorts, // options } = params; // 修改为使用FILTER可以利用索引 const filterAql = this.getFilterAql(filter); // 拼装排序条件 默认创建时间倒序 const sortAql = this.getSortAql(this.getSortFieldAqlList(sorts)); const collection = arangojs_1.aql.literal(`${this.tableName}`); const query = (0, arangojs_1.aql) ` FOR t IN ${collection} FILTER t._status == true ${filterAql} ${sortAql} RETURN t`; const rows = await this.executeSql({ sql: query.query, binds: query.bindVars }); return rows; } catch (err) { console.error("ArangodbRepository getsByFilter 失败!!!", err); throw Error(`ArangodbRepository getsByFilter 失败!!!, 错误: ${err}`); } } /** * update document by _id && newObj from collection * @param {object} _params - the _id of the document * @param {string} _params.filter - the _id of the document * @param {object} _params.newObj - the newObj of the document * @return {AqlQuery} - interface AqlQuery by arangodb */ async updatesByFilter(params) { try { await JoiUtils_1.JoiUtils.checkParams(RepositoryParams_1.UpdatesByFilterParamsSchema, params); let { filter, newObj, // options } = params; const update_date = moment().format('YYYY-MM-DD HH:mm:ss'); const filterAql = this.getFilterAql(filter); const collection = arangojs_1.aql.literal(`${this.tableName}`); // todo add returns 返回 NEW. etc. const query = (0, arangojs_1.aql) ` let tsl = ( FOR t IN ${collection} FILTER t._status == true ${filterAql} UPDATE t WITH MERGE(UNSET(${newObj}, ${this.unset}), { _update_date:${update_date}}) IN ${collection} OPTIONS { keepNull: false } RETURN NEW._id ) RETURN {ids: tsl}`; const rows = await this.executeSql({ sql: query.query, binds: query.bindVars }); return rows[0]; } catch (err) { console.error("ArangodbRepository updatesByFilter 失败!!!", err); throw Error(`ArangodbRepository updatesByFilter 失败!!!, 错误: ${err}`); } } async saves(params) { try { await JoiUtils_1.JoiUtils.checkParams(RepositoryParams_1.SavesParamsSchema, params); let { objs, // options } = params; //todo 检查Entity attributes const create_date = moment().format('YYYY-MM-DD HH:mm:ss'); const collection = arangojs_1.aql.literal(`${this.tableName}`); const query = (0, arangojs_1.aql) ` let tsl = ( FOR t IN ${objs} INSERT MERGE(UNSET(t, ${this.unset}), { _create_date:${create_date}, _status: true }) INTO ${collection} RETURN NEW._id ) RETURN {ids: tsl}`; const rows = await this.executeSql({ sql: query.query, binds: query.bindVars }); return rows[0]; } catch (err) { console.error("ArangodbRepository save 失败!!!", err); throw Error(`ArangodbRepository save 失败!!!, 错误: ${err}`); } } async deletesByFilter(params) { try { await JoiUtils_1.JoiUtils.checkParams(RepositoryParams_1.DeletesByFilterParamsSchema, params); let { filter, // options } = params; const delete_date = moment().format('YYYY-MM-DD HH:mm:ss'); const filterAql = this.getFilterAql(filter); const collection = arangojs_1.aql.literal(`${this.tableName}`); const query = (0, arangojs_1.aql) ` let tsl = ( FOR t IN ${collection} FILTER t._status == true ${filterAql} UPDATE t WITH MERGE(${{ _status: false }}, { _delete_date:${delete_date}}) IN ${collection} OPTIONS { keepNull: false } RETURN NEW._id ) RETURN {ids: tsl}`; const rows = await this.executeSql({ sql: query.query, binds: query.bindVars }); return rows[0]; } catch (err) { console.error("ArangodbRepository deletesByFilter 失败!!!", err); throw Error(`ArangodbRepository deletesByFilter 失败!!!, 错误: ${err}`); } } } exports.ArangodbRepository = ArangodbRepository; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQXJhbmdvZGJSZXBvc2l0b3J5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiQXJhbmdvZGJSZXBvc2l0b3J5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUNBLCtCQUErQjtBQUMvQixpQ0FBaUM7QUFDakMsdUNBQStCO0FBQy9CLGdFQWFtQztBQUNuQyxrREFBK0M7QUFDL0Msd0RBQXdEO0FBQ3hELGdEQUFtRDtBQUVuRDs7O0dBR0c7QUFDSCxNQUFhLGtCQUFrQjtJQW9CM0IsNEVBQTRFO0lBQzVFLGNBQWM7SUFDZCw0RUFBNEU7SUFDNUUsWUFBWSxXQUFnQixFQUFFLE9BQVk7UUFOMUMsaUNBQWlDO1FBQ2pDLFVBQUssR0FBRyxDQUFDLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxjQUFjLENBQUMsQ0FBQztRQU12RCxzQkFBc0I7UUFDdEIsSUFBSTtZQUNBLElBQUksQ0FBQyxPQUFPLEVBQUU7Z0JBQ1YsTUFBTSxLQUFLLENBQUMsMENBQTBDLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDO2FBQ3hGO1lBQ0QsSUFBSSxDQUFDLFVBQVUsR0FBRyxXQUFXLENBQUM7WUFDOUIsaURBQWlEO1lBQ2pELElBQUksQ0FBQyxNQUFNLEdBQUcsT0FBTyxDQUFDO1lBQ3RCLElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBQSx1QkFBYSxFQUFDLE9BQU8sQ0FBQyxDQUFDO1NBQzNDO1FBQUMsT0FBTyxHQUFHLEVBQUU7WUFDVixNQUFNO1lBQ04sT0FBTyxDQUFDLEtBQUssQ0FBQyxvQ0FBb0MsRUFBRSxHQUFHLENBQUMsQ0FBQztTQUM1RDtRQUNELEtBQUs7SUFDVCxDQUFDO0lBRUQsNEVBQTRFO0lBQzVFLGlCQUFpQjtJQUNqQiw0RUFBNEU7SUFFNUUsS0FBSyxDQUFDLFVBQVUsQ0FBQyxNQUF3QjtRQUNyQyxJQUFJO1lBQ0EsTUFBTSxtQkFBUSxDQUFDLFdBQVcsQ0FBQyx5Q0FBc0IsRUFB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