UNPKG

@kitmi/data

Version:

Jacaranda Framework Data Access Model

229 lines (228 loc) 8.81 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "default", { enumerable: true, get: function() { return _default; } }); const _utils = require("@kitmi/utils"); const _EntityModel = /*#__PURE__*/ _interop_require_default(require("../relational/EntityModel")); const _types = require("@kitmi/types"); const _allSync = require("@kitmi/validators/allSync"); const _helpers = require("../../helpers"); function _interop_require_default(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const defaultNestedKeyGetter = (anchor)=>':' + anchor; /** * PostgresEntityModel entity model class. */ class PostgresEntityModel extends _EntityModel.default { get errCodeDuplicate() { return '23505'; } /** * [override] Serialize value into database acceptable format. * @param {object} name - Name of the symbol token */ _translateSymbolToken(name) { if (name === 'NOW') { return (0, _helpers.xrCall)('NOW'); } throw new Error('not support: ' + name); } /** * [override] * @param {*} value * @param {*} info */ _serializeByTypeInfo(value, info) { if (info.type === 'boolean') { return value ? true : false; } if (info.type === 'datetime') { return _allSync.Types.DATETIME.serialize(value); } if (info.type === 'array' && Array.isArray(value)) { if (info.csv) { return _allSync.Types.ARRAY.toCsv(value); } else { return value; } } /* postgres support jsonb if (info.type === 'object') { return Types.OBJECT.serialize(value); } */ return value; } /** * * @param {Object} result * @param {*} hierarchy * @param {*} nestedKeyGetter * @returns {*} */ _mapRecordsToObjects(result, hierarchy, nestedKeyGetter) { const { data, fields, aliases } = result; nestedKeyGetter == null && (nestedKeyGetter = defaultNestedKeyGetter); const aliasMap = _utils._.mapValues(aliases, (chain)=>chain.map((anchor)=>nestedKeyGetter(anchor))); //console.log(fields, aliasMap); const mainIndex = {}; const self = this; // map postgres fields result into array of { table <table alias>, name: <column name> } const columns = fields.map((col)=>{ const l = col.name.length - 1; if (col.name[l] === '$') { return { table: col.name.substring(0, l) }; } return { table: 'A', name: col.name }; }); // map flat record into hierachy function mergeRecord(existingRow, rowObject, associations, nodePath) { return _utils._.each(associations, ({ sql, key, list, subAssocs }, anchor)=>{ if (sql) return; const currentPath = nodePath.concat(); currentPath.push(anchor); const objKey = nestedKeyGetter(anchor); const subObj = rowObject[objKey]; if (!subObj) { // associated entity not in result set, probably when custom projection is used return; } const subIndexes = existingRow.subIndexes[objKey]; // joined an empty record const rowKeyValue = subObj[key]; if (_utils._.isNil(rowKeyValue)) { if (list && rowKeyValue == null) { if (existingRow.rowObject[objKey]) { existingRow.rowObject[objKey].push(subObj); } else { existingRow.rowObject[objKey] = [ subObj ]; } } return; } const existingSubRow = subIndexes && subIndexes[rowKeyValue]; if (existingSubRow) { if (subAssocs) { return mergeRecord(existingSubRow, subObj, subAssocs, currentPath); } } else { if (!list) { throw new _types.ApplicationError(`The structure of association "${currentPath.join('.')}" with [key=${key}] of entity "${self.meta.name}" should be a list.`, { existingRow, rowObject }); } if (existingRow.rowObject[objKey]) { existingRow.rowObject[objKey].push(subObj); } else { existingRow.rowObject[objKey] = [ subObj ]; } const subIndex = { rowObject: subObj }; if (subAssocs) { subIndex.subIndexes = buildSubIndexes(subObj, subAssocs); } if (!subIndexes) { throw new _types.ApplicationError(`The subIndexes of association "${currentPath.join('.')}" with [key=${key}] of entity "${self.meta.name}" does not exist.`, { existingRow, rowObject }); } subIndexes[rowKeyValue] = subIndex; } }); } // build sub index for list member function buildSubIndexes(rowObject, associations) { const indexes = {}; _utils._.each(associations, ({ sql, key, list, subAssocs }, anchor)=>{ if (sql) { return; } const objKey = nestedKeyGetter(anchor); let subObject = rowObject[objKey]; const subIndex = { rowObject: subObject }; if (list) { if (!subObject) { // associated entity not in result set, probably when custom projection is used rowObject[objKey] = []; return; } // many to * if (subObject[key] == null) { // when custom projection is used subObject = null; rowObject[objKey] = []; } else { rowObject[objKey] = [ subObject ]; } } if (subObject) { if (subAssocs) { subIndex.subIndexes = buildSubIndexes(subObject, subAssocs); } indexes[objKey] = subObject[key] ? { [subObject[key]]: subIndex } : {}; } }); return indexes; } const arrayOfObjs = []; // process each row data.forEach((row)=>{ const tableCache = {}; // from alias to child prop of rowObject // hash-style data row const rowObject = row.reduce((result, value, colIdx)=>{ const col = columns[colIdx]; if (col.table === 'A') { result[col.name] = value; } else { // avoid a object with all null value exists tableCache[col.table] = value; } return result; }, {}); _utils._.forOwn(tableCache, (obj, table)=>{ const nodePath = aliasMap[table]; let node = rowObject; for(let i = 0; i < nodePath.length; i++){ const objKey = nodePath[i]; node = node[objKey] = node[objKey] || {}; } Object.assign(node, obj); }); const rowKey = rowObject[self.meta.keyField]; const existingRow = mainIndex[rowKey]; if (existingRow) { return mergeRecord(existingRow, rowObject, hierarchy, []); } arrayOfObjs.push(rowObject); mainIndex[rowKey] = { rowObject, subIndexes: buildSubIndexes(rowObject, hierarchy) }; }); return arrayOfObjs; } } const _default = PostgresEntityModel; //# sourceMappingURL=EntityModel.js.map