diff --git a/packages/nocodb/src/db/BaseModelSqlv2.ts b/packages/nocodb/src/db/BaseModelSqlv2.ts index 162a8cc696..ecda3a98e6 100644 --- a/packages/nocodb/src/db/BaseModelSqlv2.ts +++ b/packages/nocodb/src/db/BaseModelSqlv2.ts @@ -1,7 +1,7 @@ -import autoBind from 'auto-bind' -import groupBy from 'lodash/groupBy' -import DataLoader from 'dataloader' -import { nocoExecute } from 'nc-help' +import autoBind from 'auto-bind'; +import groupBy from 'lodash/groupBy'; +import DataLoader from 'dataloader'; +import { nocoExecute } from 'nc-help'; import { AuditOperationSubTypes, AuditOperationTypes, @@ -9,33 +9,33 @@ import { isVirtualCol, RelationTypes, UITypes, -} from 'nocodb-sdk' -import Validator from 'validator' -import { customAlphabet } from 'nanoid' -import DOMPurify from 'isomorphic-dompurify' -import { v4 as uuidv4 } from 'uuid' -import { NcError } from '../helpers/catchError' -import getAst from '../helpers/getAst' - -import { Audit, Column, Filter, Model, Project, Sort, View } from '../models' -import { sanitize, unsanitize } from '../helpers/sqlSanitize' +} from 'nocodb-sdk'; +import Validator from 'validator'; +import { customAlphabet } from 'nanoid'; +import DOMPurify from 'isomorphic-dompurify'; +import { v4 as uuidv4 } from 'uuid'; +import { NcError } from '../helpers/catchError'; +import getAst from '../helpers/getAst'; + +import { Audit, Column, Filter, Model, Project, Sort, View } from '../models'; +import { sanitize, unsanitize } from '../helpers/sqlSanitize'; import { COMPARISON_OPS, COMPARISON_SUB_OPS, IS_WITHIN_COMPARISON_SUB_OPS, -} from '../models/Filter' -import Noco from '../Noco' -import { HANDLE_WEBHOOK } from '../services/hook-handler.service' -import formulaQueryBuilderv2 from './formulav2/formulaQueryBuilderv2' -import genRollupSelectv2 from './genRollupSelectv2' -import conditionV2 from './conditionV2' -import sortV2 from './sortV2' -import { customValidators } from './util/customValidators' -import type { XKnex } from './CustomKnex' +} from '../models/Filter'; +import Noco from '../Noco'; +import { HANDLE_WEBHOOK } from '../services/hook-handler.service'; +import formulaQueryBuilderv2 from './formulav2/formulaQueryBuilderv2'; +import genRollupSelectv2 from './genRollupSelectv2'; +import conditionV2 from './conditionV2'; +import sortV2 from './sortV2'; +import { customValidators } from './util/customValidators'; +import type { XKnex } from './CustomKnex'; import type { XcFilter, XcFilterWithAlias, -} from './sql-data-mapper/lib/BaseModel' +} from './sql-data-mapper/lib/BaseModel'; import type { BarcodeColumn, FormulaColumn, @@ -44,41 +44,41 @@ import type { QrCodeColumn, RollupColumn, SelectOption, -} from '../models' -import type { Knex } from 'knex' -import type { SortType } from 'nocodb-sdk' +} from '../models'; +import type { Knex } from 'knex'; +import type { SortType } from 'nocodb-sdk'; -const GROUP_COL = '__nc_group_id' +const GROUP_COL = '__nc_group_id'; -const nanoidv2 = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz', 14) +const nanoidv2 = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz', 14); export async function getViewAndModelByAliasOrId(param: { projectName: string; tableName: string; viewName?: string; }) { - const project = await Project.getWithInfoByTitleOrId(param.projectName) + const project = await Project.getWithInfoByTitleOrId(param.projectName); const model = await Model.getByAliasOrId({ project_id: project.id, aliasOrId: param.tableName, - }) + }); const view = param.viewName && (await View.getByTitleOrId({ titleOrId: param.viewName, fk_model_id: model.id, - })) - if (!model) NcError.notFound('Table not found') - return { model, view } + })); + if (!model) NcError.notFound('Table not found'); + return { model, view }; } async function populatePk(model: Model, insertObj: any) { - await model.getColumns() + await model.getColumns(); for (const pkCol of model.primaryKeys) { - if (!pkCol.meta?.ag || insertObj[pkCol.title]) continue + if (!pkCol.meta?.ag || insertObj[pkCol.title]) continue; insertObj[pkCol.title] = - pkCol.meta?.ag === 'nc' ? `rc_${nanoidv2()}` : uuidv4() + pkCol.meta?.ag === 'nc' ? `rc_${nanoidv2()}` : uuidv4(); } } @@ -88,13 +88,13 @@ function checkColumnRequired( extractPkAndPv?: boolean, ) { // if primary key or foreign key included in fields, it's required - if (column.pk || column.uidt === UITypes.ForeignKey) return true + if (column.pk || column.uidt === UITypes.ForeignKey) return true; - if (extractPkAndPv && column.pv) return true + if (extractPkAndPv && column.pv) return true; // check fields defined and if not, then select all // if defined check if it is in the fields - return !fields || fields.includes(column.title) + return !fields || fields.includes(column.title); } /** @@ -104,30 +104,30 @@ function checkColumnRequired( * @classdesc Base class for models */ class BaseModelSqlv2 { - protected dbDriver: XKnex - protected model: Model - protected viewId: string - private _proto: any - private _columns = {} + protected dbDriver: XKnex; + protected model: Model; + protected viewId: string; + private _proto: any; + private _columns = {}; private config: any = { limitDefault: Math.max(+process.env.DB_QUERY_LIMIT_DEFAULT || 25, 1), limitMin: Math.max(+process.env.DB_QUERY_LIMIT_MIN || 1, 1), limitMax: Math.max(+process.env.DB_QUERY_LIMIT_MAX || 1000, 1), - } + }; constructor({ - dbDriver, - model, - viewId, - }: { + dbDriver, + model, + viewId, + }: { [key: string]: any; model: Model; }) { - this.dbDriver = dbDriver - this.model = model - this.viewId = viewId - autoBind(this) + this.dbDriver = dbDriver; + this.model = model; + this.viewId = viewId; + autoBind(this); } public async readByPk( @@ -135,55 +135,55 @@ class BaseModelSqlv2 { validateFormula = false, query: any = {}, ): Promise { - const qb = this.dbDriver(this.tnPath) + const qb = this.dbDriver(this.tnPath); const { ast, dependencyFields } = await getAst({ query, model: this.model, view: this.viewId && (await View.get(this.viewId)), - }) + }); await this.selectObject({ ...(dependencyFields ?? {}), qb, validateFormula, - }) + }); - qb.where(_wherePk(this.model.primaryKeys, id)) + qb.where(_wherePk(this.model.primaryKeys, id)); - let data + let data; try { - data = (await this.execAndParse(qb))?.[0] + data = (await this.execAndParse(qb))?.[0]; } catch (e) { if (validateFormula || !haveFormulaColumn(await this.model.getColumns())) - throw e - console.log(e) - return this.readByPk(id, true) + throw e; + console.log(e); + return this.readByPk(id, true); } if (data) { - const proto = await this.getProto() - data.__proto__ = proto + const proto = await this.getProto(); + data.__proto__ = proto; } - return data ? await nocoExecute(ast, data, {}, query) : {} + return data ? await nocoExecute(ast, data, {}, query) : {}; } public async exist(id?: any): Promise { - const qb = this.dbDriver(this.tnPath) - await this.model.getColumns() - const pks = this.model.primaryKeys + const qb = this.dbDriver(this.tnPath); + await this.model.getColumns(); + const pks = this.model.primaryKeys; - if (!pks.length) return false + if (!pks.length) return false; - qb.select(pks[0].column_name) + qb.select(pks[0].column_name); if ((id + '').split('___').length != pks?.length) { - return false + return false; } - qb.where(_wherePk(pks, id)).first() - return !!(await qb) + qb.where(_wherePk(pks, id)).first(); + return !!(await qb); } // todo: add support for sortArrJson @@ -195,13 +195,13 @@ class BaseModelSqlv2 { } = {}, validateFormula = false, ): Promise { - const { where, ...rest } = this._getListArgs(args as any) - const qb = this.dbDriver(this.tnPath) - await this.selectObject({ ...args, qb, validateFormula }) + const { where, ...rest } = this._getListArgs(args as any); + const qb = this.dbDriver(this.tnPath); + await this.selectObject({ ...args, qb, validateFormula }); - const aliasColObjMap = await this.model.getAliasColObjMap() - const sorts = extractSortsObject(rest?.sort, aliasColObjMap) - const filterObj = extractFilterFromXwhere(where, aliasColObjMap) + const aliasColObjMap = await this.model.getAliasColObjMap(); + const sorts = extractSortsObject(rest?.sort, aliasColObjMap); + const filterObj = extractFilterFromXwhere(where, aliasColObjMap); await conditionV2( [ @@ -218,30 +218,30 @@ class BaseModelSqlv2 { ], qb, this.dbDriver, - ) + ); if (Array.isArray(sorts) && sorts?.length) { - await sortV2(sorts, qb, this.dbDriver) + await sortV2(sorts, qb, this.dbDriver); } else if (this.model.primaryKey) { - qb.orderBy(this.model.primaryKey.column_name) + qb.orderBy(this.model.primaryKey.column_name); } - let data + let data; try { - data = await qb.first() + data = await qb.first(); } catch (e) { if (validateFormula || !haveFormulaColumn(await this.model.getColumns())) - throw e - console.log(e) - return this.findOne(args, true) + throw e; + console.log(e); + return this.findOne(args, true); } if (data) { - const proto = await this.getProto() - data.__proto__ = proto + const proto = await this.getProto(); + data.__proto__ = proto; } - return data + return data; } public async list( @@ -257,23 +257,23 @@ class BaseModelSqlv2 { ignoreViewFilterAndSort = false, validateFormula = false, ): Promise { - const { where, fields, ...rest } = this._getListArgs(args as any) + const { where, fields, ...rest } = this._getListArgs(args as any); - const qb = this.dbDriver(this.tnPath) + const qb = this.dbDriver(this.tnPath); await this.selectObject({ qb, fieldsSet: args.fieldsSet, viewId: this.viewId, validateFormula, - }) + }); if (+rest?.shuffle) { - await this.shuffle({ qb }) + await this.shuffle({ qb }); } - const aliasColObjMap = await this.model.getAliasColObjMap() - let sorts = extractSortsObject(rest?.sort, aliasColObjMap) - const filterObj = extractFilterFromXwhere(where, aliasColObjMap) + const aliasColObjMap = await this.model.getAliasColObjMap(); + let sorts = extractSortsObject(rest?.sort, aliasColObjMap); + const filterObj = extractFilterFromXwhere(where, aliasColObjMap); // todo: replace with view id if (!ignoreViewFilterAndSort && this.viewId) { await conditionV2( @@ -296,14 +296,14 @@ class BaseModelSqlv2 { ], qb, this.dbDriver, - ) + ); if (!sorts) sorts = args.sortArr?.length ? args.sortArr - : await Sort.list({ viewId: this.viewId }) + : await Sort.list({ viewId: this.viewId }); - await sortV2(sorts, qb, this.dbDriver) + await sortV2(sorts, qb, this.dbDriver); } else { await conditionV2( [ @@ -320,52 +320,52 @@ class BaseModelSqlv2 { ], qb, this.dbDriver, - ) + ); - if (!sorts) sorts = args.sortArr + if (!sorts) sorts = args.sortArr; - await sortV2(sorts, qb, this.dbDriver) + await sortV2(sorts, qb, this.dbDriver); } // sort by primary key if not autogenerated string // if autogenerated string sort by created_at column if present if (this.model.primaryKey && this.model.primaryKey.ai) { - qb.orderBy(this.model.primaryKey.column_name) + qb.orderBy(this.model.primaryKey.column_name); } else if (this.model.columns.find((c) => c.column_name === 'created_at')) { - qb.orderBy('created_at') + qb.orderBy('created_at'); } - if (!ignoreViewFilterAndSort) applyPaginate(qb, rest) - const proto = await this.getProto() + if (!ignoreViewFilterAndSort) applyPaginate(qb, rest); + const proto = await this.getProto(); - let data + let data; try { - data = await this.execAndParse(qb) + data = await this.execAndParse(qb); } catch (e) { if (validateFormula || !haveFormulaColumn(await this.model.getColumns())) - throw e - console.log(e) - return this.list(args, ignoreViewFilterAndSort, true) + throw e; + console.log(e); + return this.list(args, ignoreViewFilterAndSort, true); } return data?.map((d) => { - d.__proto__ = proto - return d - }) + d.__proto__ = proto; + return d; + }); } public async count( args: { where?: string; limit?; filterArr?: Filter[] } = {}, ignoreViewFilterAndSort = false, ): Promise { - await this.model.getColumns() - const { where } = this._getListArgs(args) + await this.model.getColumns(); + const { where } = this._getListArgs(args); - const qb = this.dbDriver(this.tnPath) + const qb = this.dbDriver(this.tnPath); // qb.xwhere(where, await this.model.getAliasColMapping()); - const aliasColObjMap = await this.model.getAliasColObjMap() - const filterObj = extractFilterFromXwhere(where, aliasColObjMap) + const aliasColObjMap = await this.model.getAliasColObjMap(); + const filterObj = extractFilterFromXwhere(where, aliasColObjMap); if (!ignoreViewFilterAndSort && this.viewId) { await conditionV2( @@ -389,7 +389,7 @@ class BaseModelSqlv2 { ], qb, this.dbDriver, - ) + ); } else { await conditionV2( [ @@ -407,22 +407,22 @@ class BaseModelSqlv2 { ], qb, this.dbDriver, - ) + ); } qb.count(sanitize(this.model.primaryKey?.column_name) || '*', { as: 'count', - }).first() + }).first(); - let sql = sanitize(qb.toQuery()) + let sql = sanitize(qb.toQuery()); if (!this.isPg && !this.isMssql && !this.isSnowflake) { - sql = unsanitize(qb.toQuery()) + sql = unsanitize(qb.toQuery()); } - const res = (await this.dbDriver.raw(sql)) as any + const res = (await this.dbDriver.raw(sql)) as any; return (this.isPg || this.isSnowflake ? res.rows[0] : res[0][0] ?? res[0]) - .count + .count; } // todo: add support for sortArrJson and filterArrJson @@ -437,21 +437,21 @@ class BaseModelSqlv2 { column_name: '', }, ) { - const { where, ...rest } = this._getListArgs(args as any) + const { where, ...rest } = this._getListArgs(args as any); - const qb = this.dbDriver(this.tnPath) - qb.count(`${this.model.primaryKey?.column_name || '*'} as count`) - qb.select(args.column_name) + const qb = this.dbDriver(this.tnPath); + qb.count(`${this.model.primaryKey?.column_name || '*'} as count`); + qb.select(args.column_name); if (+rest?.shuffle) { - await this.shuffle({ qb }) + await this.shuffle({ qb }); } - const aliasColObjMap = await this.model.getAliasColObjMap() + const aliasColObjMap = await this.model.getAliasColObjMap(); - const sorts = extractSortsObject(rest?.sort, aliasColObjMap) + const sorts = extractSortsObject(rest?.sort, aliasColObjMap); - const filterObj = extractFilterFromXwhere(where, aliasColObjMap) + const filterObj = extractFilterFromXwhere(where, aliasColObjMap); await conditionV2( [ new Filter({ @@ -462,11 +462,11 @@ class BaseModelSqlv2 { ], qb, this.dbDriver, - ) - qb.groupBy(args.column_name) - if (sorts) await sortV2(sorts, qb, this.dbDriver) - applyPaginate(qb, rest) - return await qb + ); + qb.groupBy(args.column_name); + if (sorts) await sortV2(sorts, qb, this.dbDriver); + applyPaginate(qb, rest); + return await qb; } async multipleHmList( @@ -474,38 +474,38 @@ class BaseModelSqlv2 { args: { limit?; offset?; fieldsSet?: Set } = {}, ) { try { - const { where, sort, ...rest } = this._getListArgs(args as any) + const { where, sort, ...rest } = this._getListArgs(args as any); // todo: get only required fields // const { cn } = this.hasManyRelations.find(({ tn }) => tn === child) || {}; const relColumn = (await this.model.getColumns()).find( (c) => c.id === colId, - ) + ); const chilCol = await ( (await relColumn.getColOptions()) as LinkToAnotherRecordColumn - ).getChildColumn() - const childTable = await chilCol.getModel() + ).getChildColumn(); + const childTable = await chilCol.getModel(); const parentCol = await ( (await relColumn.getColOptions()) as LinkToAnotherRecordColumn - ).getParentColumn() - const parentTable = await parentCol.getModel() + ).getParentColumn(); + const parentTable = await parentCol.getModel(); const childModel = await Model.getBaseModelSQL({ model: childTable, dbDriver: this.dbDriver, - }) - await parentTable.getColumns() + }); + await parentTable.getColumns(); - const childTn = this.getTnPath(childTable) - const parentTn = this.getTnPath(parentTable) + const childTn = this.getTnPath(childTable); + const parentTn = this.getTnPath(parentTable); - const qb = this.dbDriver(childTn) + const qb = this.dbDriver(childTn); await childModel.selectObject({ qb, extractPkAndPv: true, fieldsSet: args.fieldsSet, - }) - await this.applySortAndFilter({ table: childTable, where, qb, sort }) + }); + await this.applySortAndFilter({ table: childTable, where, qb, sort }); const childQb = this.dbDriver.queryBuilder().from( this.dbDriver @@ -520,59 +520,59 @@ class BaseModelSqlv2 { .select(parentCol.column_name) // .where(parentTable.primaryKey.cn, p) .where(_wherePk(parentTable.primaryKeys, p)), - ) + ); // todo: sanitize - query.limit(+rest?.limit || 25) - query.offset(+rest?.offset || 0) + query.limit(+rest?.limit || 25); + query.offset(+rest?.offset || 0); - return this.isSqlite ? this.dbDriver.select().from(query) : query + return this.isSqlite ? this.dbDriver.select().from(query) : query; }), !this.isSqlite, ) .as('list'), - ) + ); // console.log(childQb.toQuery()) - const children = await this.execAndParse(childQb, childTable) + const children = await this.execAndParse(childQb, childTable); const proto = await ( await Model.getBaseModelSQL({ id: childTable.id, dbDriver: this.dbDriver, }) - ).getProto() + ).getProto(); return groupBy( children.map((c) => { - c.__proto__ = proto - return c + c.__proto__ = proto; + return c; }), GROUP_COL, - ) + ); } catch (e) { - console.log(e) - throw e + console.log(e); + throw e; } } private async applySortAndFilter({ - table, - where, - qb, - sort, - }: { + table, + where, + qb, + sort, + }: { table: Model; where: string; qb; sort: string; }) { - const childAliasColMap = await table.getAliasColObjMap() + const childAliasColMap = await table.getAliasColObjMap(); - const filter = extractFilterFromXwhere(where, childAliasColMap) - await conditionV2(filter, qb, this.dbDriver) - if (!sort) return - const sortObj = extractSortsObject(sort, childAliasColMap) - if (sortObj) await sortV2(sortObj, qb, this.dbDriver) + const filter = extractFilterFromXwhere(where, childAliasColMap); + await conditionV2(filter, qb, this.dbDriver); + if (!sort) return; + const sortObj = extractSortsObject(sort, childAliasColMap); + if (sortObj) await sortV2(sortObj, qb, this.dbDriver); } async multipleHmListCount({ colId, ids }) { @@ -580,19 +580,19 @@ class BaseModelSqlv2 { // const { cn } = this.hasManyRelations.find(({ tn }) => tn === child) || {}; const relColumn = (await this.model.getColumns()).find( (c) => c.id === colId, - ) + ); const chilCol = await ( (await relColumn.getColOptions()) as LinkToAnotherRecordColumn - ).getChildColumn() - const childTable = await chilCol.getModel() + ).getChildColumn(); + const childTable = await chilCol.getModel(); const parentCol = await ( (await relColumn.getColOptions()) as LinkToAnotherRecordColumn - ).getParentColumn() - const parentTable = await parentCol.getModel() - await parentTable.getColumns() + ).getParentColumn(); + const parentTable = await parentCol.getModel(); + await parentTable.getColumns(); - const childTn = this.getTnPath(childTable) - const parentTn = this.getTnPath(parentTable) + const childTn = this.getTnPath(childTable); + const parentTn = this.getTnPath(parentTable); const children = await this.dbDriver.unionAll( ids.map((p) => { @@ -605,17 +605,17 @@ class BaseModelSqlv2 { // .where(parentTable.primaryKey.cn, p) .where(_wherePk(parentTable.primaryKeys, p)), ) - .first() + .first(); - return this.isSqlite ? this.dbDriver.select().from(query) : query + return this.isSqlite ? this.dbDriver.select().from(query) : query; }), !this.isSqlite, - ) + ); - return children.map(({ count }) => count) + return children.map(({ count }) => count); } catch (e) { - console.log(e) - throw e + console.log(e); + throw e; } } @@ -624,32 +624,32 @@ class BaseModelSqlv2 { args: { limit?; offset?; fieldSet?: Set } = {}, ) { try { - const { where, sort, ...rest } = this._getListArgs(args as any) + const { where, sort, ...rest } = this._getListArgs(args as any); // todo: get only required fields const relColumn = (await this.model.getColumns()).find( (c) => c.id === colId, - ) + ); const chilCol = await ( (await relColumn.getColOptions()) as LinkToAnotherRecordColumn - ).getChildColumn() - const childTable = await chilCol.getModel() + ).getChildColumn(); + const childTable = await chilCol.getModel(); const parentCol = await ( (await relColumn.getColOptions()) as LinkToAnotherRecordColumn - ).getParentColumn() - const parentTable = await parentCol.getModel() + ).getParentColumn(); + const parentTable = await parentCol.getModel(); const childModel = await Model.getBaseModelSQL({ model: childTable, dbDriver: this.dbDriver, - }) - await parentTable.getColumns() + }); + await parentTable.getColumns(); - const childTn = this.getTnPath(childTable) - const parentTn = this.getTnPath(parentTable) + const childTn = this.getTnPath(childTable); + const parentTn = this.getTnPath(parentTable); - const qb = this.dbDriver(childTn) - await this.applySortAndFilter({ table: childTable, where, qb, sort }) + const qb = this.dbDriver(childTn); + await this.applySortAndFilter({ table: childTable, where, qb, sort }); qb.whereIn( chilCol.column_name, @@ -657,29 +657,29 @@ class BaseModelSqlv2 { .select(parentCol.column_name) // .where(parentTable.primaryKey.cn, p) .where(_wherePk(parentTable.primaryKeys, id)), - ) + ); // todo: sanitize - qb.limit(+rest?.limit || 25) - qb.offset(+rest?.offset || 0) + qb.limit(+rest?.limit || 25); + qb.offset(+rest?.offset || 0); - await childModel.selectObject({ qb, fieldsSet: args.fieldSet }) + await childModel.selectObject({ qb, fieldsSet: args.fieldSet }); - const children = await this.execAndParse(qb, childTable) + const children = await this.execAndParse(qb, childTable); const proto = await ( await Model.getBaseModelSQL({ id: childTable.id, dbDriver: this.dbDriver, }) - ).getProto() + ).getProto(); return children.map((c) => { - c.__proto__ = proto - return c - }) + c.__proto__ = proto; + return c; + }); } catch (e) { - console.log(e) - throw e + console.log(e); + throw e; } } @@ -688,19 +688,19 @@ class BaseModelSqlv2 { // const { cn } = this.hasManyRelations.find(({ tn }) => tn === child) || {}; const relColumn = (await this.model.getColumns()).find( (c) => c.id === colId, - ) + ); const chilCol = await ( (await relColumn.getColOptions()) as LinkToAnotherRecordColumn - ).getChildColumn() - const childTable = await chilCol.getModel() + ).getChildColumn(); + const childTable = await chilCol.getModel(); const parentCol = await ( (await relColumn.getColOptions()) as LinkToAnotherRecordColumn - ).getParentColumn() - const parentTable = await parentCol.getModel() - await parentTable.getColumns() + ).getParentColumn(); + const parentTable = await parentCol.getModel(); + await parentTable.getColumns(); - const childTn = this.getTnPath(childTable) - const parentTn = this.getTnPath(parentTable) + const childTn = this.getTnPath(childTable); + const parentTn = this.getTnPath(parentTable); const query = this.dbDriver(childTn) .count(`${chilCol?.column_name} as count`) @@ -710,12 +710,12 @@ class BaseModelSqlv2 { .select(parentCol.column_name) .where(_wherePk(parentTable.primaryKeys, id)), ) - .first() - const { count } = await query - return count + .first(); + const { count } = await query; + return count; } catch (e) { - console.log(e) - throw e + console.log(e); + throw e; } } @@ -723,40 +723,40 @@ class BaseModelSqlv2 { { colId, parentIds }, args: { limit?; offset?; fieldsSet?: Set } = {}, ) { - const { where, sort, ...rest } = this._getListArgs(args as any) + const { where, sort, ...rest } = this._getListArgs(args as any); const relColumn = (await this.model.getColumns()).find( (c) => c.id === colId, - ) + ); const relColOptions = - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn + (await relColumn.getColOptions()) as LinkToAnotherRecordColumn; // const tn = this.model.tn; // const cn = (await relColOptions.getChildColumn()).title; - const mmTable = await relColOptions.getMMModel() - const vtn = this.getTnPath(mmTable) - const vcn = (await relColOptions.getMMChildColumn()).column_name - const vrcn = (await relColOptions.getMMParentColumn()).column_name - const rcn = (await relColOptions.getParentColumn()).column_name - const cn = (await relColOptions.getChildColumn()).column_name - const childTable = await (await relColOptions.getParentColumn()).getModel() - const parentTable = await (await relColOptions.getChildColumn()).getModel() - await parentTable.getColumns() + const mmTable = await relColOptions.getMMModel(); + const vtn = this.getTnPath(mmTable); + const vcn = (await relColOptions.getMMChildColumn()).column_name; + const vrcn = (await relColOptions.getMMParentColumn()).column_name; + const rcn = (await relColOptions.getParentColumn()).column_name; + const cn = (await relColOptions.getChildColumn()).column_name; + const childTable = await (await relColOptions.getParentColumn()).getModel(); + const parentTable = await (await relColOptions.getChildColumn()).getModel(); + await parentTable.getColumns(); const childModel = await Model.getBaseModelSQL({ dbDriver: this.dbDriver, model: childTable, - }) + }); - const childTn = this.getTnPath(childTable) - const parentTn = this.getTnPath(parentTable) + const childTn = this.getTnPath(childTable); + const parentTn = this.getTnPath(parentTable); - const rtn = childTn - const rtnId = childTable.id + const rtn = childTn; + const rtnId = childTable.id; - const qb = this.dbDriver(rtn).join(vtn, `${vtn}.${vrcn}`, `${rtn}.${rcn}`) + const qb = this.dbDriver(rtn).join(vtn, `${vtn}.${vrcn}`, `${rtn}.${rcn}`); - await childModel.selectObject({ qb, fieldsSet: args.fieldsSet }) + await childModel.selectObject({ qb, fieldsSet: args.fieldsSet }); - await this.applySortAndFilter({ table: childTable, where, qb, sort }) + await this.applySortAndFilter({ table: childTable, where, qb, sort }); const finalQb = this.dbDriver.unionAll( parentIds.map((id) => { @@ -769,69 +769,69 @@ class BaseModelSqlv2 { // .where(parentTable.primaryKey.cn, id) .where(_wherePk(parentTable.primaryKeys, id)), ) - .select(this.dbDriver.raw('? as ??', [id, GROUP_COL])) + .select(this.dbDriver.raw('? as ??', [id, GROUP_COL])); // todo: sanitize - query.limit(+rest?.limit || 25) - query.offset(+rest?.offset || 0) + query.limit(+rest?.limit || 25); + query.offset(+rest?.offset || 0); - return this.isSqlite ? this.dbDriver.select().from(query) : query + return this.isSqlite ? this.dbDriver.select().from(query) : query; }), !this.isSqlite, - ) + ); - let children = await this.execAndParse(finalQb, childTable) + let children = await this.execAndParse(finalQb, childTable); if (this.isMySQL) { - children = children[0] + children = children[0]; } const proto = await ( await Model.getBaseModelSQL({ id: rtnId, dbDriver: this.dbDriver, }) - ).getProto() + ).getProto(); const gs = groupBy( children.map((c) => { - c.__proto__ = proto - return c + c.__proto__ = proto; + return c; }), GROUP_COL, - ) - return parentIds.map((id) => gs[id] || []) + ); + return parentIds.map((id) => gs[id] || []); } public async mmList( { colId, parentId }, args: { limit?; offset?; fieldsSet?: Set } = {}, ) { - const { where, sort, ...rest } = this._getListArgs(args as any) + const { where, sort, ...rest } = this._getListArgs(args as any); const relColumn = (await this.model.getColumns()).find( (c) => c.id === colId, - ) + ); const relColOptions = - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn + (await relColumn.getColOptions()) as LinkToAnotherRecordColumn; // const tn = this.model.tn; // const cn = (await relColOptions.getChildColumn()).title; - const mmTable = await relColOptions.getMMModel() - const vtn = this.getTnPath(mmTable) - const vcn = (await relColOptions.getMMChildColumn()).column_name - const vrcn = (await relColOptions.getMMParentColumn()).column_name - const rcn = (await relColOptions.getParentColumn()).column_name - const cn = (await relColOptions.getChildColumn()).column_name - const childTable = await (await relColOptions.getParentColumn()).getModel() - const parentTable = await (await relColOptions.getChildColumn()).getModel() - await parentTable.getColumns() + const mmTable = await relColOptions.getMMModel(); + const vtn = this.getTnPath(mmTable); + const vcn = (await relColOptions.getMMChildColumn()).column_name; + const vrcn = (await relColOptions.getMMParentColumn()).column_name; + const rcn = (await relColOptions.getParentColumn()).column_name; + const cn = (await relColOptions.getChildColumn()).column_name; + const childTable = await (await relColOptions.getParentColumn()).getModel(); + const parentTable = await (await relColOptions.getChildColumn()).getModel(); + await parentTable.getColumns(); const childModel = await Model.getBaseModelSQL({ dbDriver: this.dbDriver, model: childTable, - }) + }); - const childTn = this.getTnPath(childTable) - const parentTn = this.getTnPath(parentTable) + const childTn = this.getTnPath(childTable); + const parentTn = this.getTnPath(parentTable); - const rtn = childTn - const rtnId = childTable.id + const rtn = childTn; + const rtnId = childTable.id; const qb = this.dbDriver(rtn) .join(vtn, `${vtn}.${vrcn}`, `${rtn}.${rcn}`) @@ -841,55 +841,55 @@ class BaseModelSqlv2 { .select(cn) // .where(parentTable.primaryKey.cn, id) .where(_wherePk(parentTable.primaryKeys, parentId)), - ) + ); - await childModel.selectObject({ qb, fieldsSet: args.fieldsSet }) + await childModel.selectObject({ qb, fieldsSet: args.fieldsSet }); - await this.applySortAndFilter({ table: childTable, where, qb, sort }) + await this.applySortAndFilter({ table: childTable, where, qb, sort }); // todo: sanitize - qb.limit(+rest?.limit || 25) - qb.offset(+rest?.offset || 0) + qb.limit(+rest?.limit || 25); + qb.offset(+rest?.offset || 0); - const children = await this.execAndParse(qb, childTable) + const children = await this.execAndParse(qb, childTable); const proto = await ( await Model.getBaseModelSQL({ id: rtnId, dbDriver: this.dbDriver }) - ).getProto() + ).getProto(); return children.map((c) => { - c.__proto__ = proto - return c - }) + c.__proto__ = proto; + return c; + }); } public async multipleMmListCount({ colId, parentIds }) { const relColumn = (await this.model.getColumns()).find( (c) => c.id === colId, - ) + ); const relColOptions = - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn + (await relColumn.getColOptions()) as LinkToAnotherRecordColumn; - const mmTable = await relColOptions.getMMModel() - const vtn = this.getTnPath(mmTable) - const vcn = (await relColOptions.getMMChildColumn()).column_name - const vrcn = (await relColOptions.getMMParentColumn()).column_name - const rcn = (await relColOptions.getParentColumn()).column_name - const cn = (await relColOptions.getChildColumn()).column_name - const childTable = await (await relColOptions.getParentColumn()).getModel() - const parentTable = await (await relColOptions.getChildColumn()).getModel() - await parentTable.getColumns() + const mmTable = await relColOptions.getMMModel(); + const vtn = this.getTnPath(mmTable); + const vcn = (await relColOptions.getMMChildColumn()).column_name; + const vrcn = (await relColOptions.getMMParentColumn()).column_name; + const rcn = (await relColOptions.getParentColumn()).column_name; + const cn = (await relColOptions.getChildColumn()).column_name; + const childTable = await (await relColOptions.getParentColumn()).getModel(); + const parentTable = await (await relColOptions.getChildColumn()).getModel(); + await parentTable.getColumns(); - const childTn = this.getTnPath(childTable) - const parentTn = this.getTnPath(parentTable) + const childTn = this.getTnPath(childTable); + const parentTn = this.getTnPath(parentTable); - const rtn = childTn + const rtn = childTn; const qb = this.dbDriver(rtn) .join(vtn, `${vtn}.${vrcn}`, `${rtn}.${rcn}`) // .select({ // [`${tn}_${vcn}`]: `${vtn}.${vcn}` // }) - .count(`${vtn}.${vcn}`, { as: 'count' }) + .count(`${vtn}.${vcn}`, { as: 'count' }); // await childModel.selectObject({ qb }); const children = await this.dbDriver.unionAll( @@ -903,38 +903,38 @@ class BaseModelSqlv2 { // .where(parentTable.primaryKey.cn, id) .where(_wherePk(parentTable.primaryKeys, id)), ) - .select(this.dbDriver.raw('? as ??', [id, GROUP_COL])) + .select(this.dbDriver.raw('? as ??', [id, GROUP_COL])); // this._paginateAndSort(query, { sort, limit, offset }, null, true); - return this.isSqlite ? this.dbDriver.select().from(query) : query + return this.isSqlite ? this.dbDriver.select().from(query) : query; }), !this.isSqlite, - ) + ); - const gs = groupBy(children, GROUP_COL) - return parentIds.map((id) => gs?.[id]?.[0] || []) + const gs = groupBy(children, GROUP_COL); + return parentIds.map((id) => gs?.[id]?.[0] || []); } public async mmListCount({ colId, parentId }) { const relColumn = (await this.model.getColumns()).find( (c) => c.id === colId, - ) + ); const relColOptions = - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn + (await relColumn.getColOptions()) as LinkToAnotherRecordColumn; - const mmTable = await relColOptions.getMMModel() - const vtn = this.getTnPath(mmTable) - const vcn = (await relColOptions.getMMChildColumn()).column_name - const vrcn = (await relColOptions.getMMParentColumn()).column_name - const rcn = (await relColOptions.getParentColumn()).column_name - const cn = (await relColOptions.getChildColumn()).column_name - const childTable = await (await relColOptions.getParentColumn()).getModel() - const parentTable = await (await relColOptions.getChildColumn()).getModel() - await parentTable.getColumns() + const mmTable = await relColOptions.getMMModel(); + const vtn = this.getTnPath(mmTable); + const vcn = (await relColOptions.getMMChildColumn()).column_name; + const vrcn = (await relColOptions.getMMParentColumn()).column_name; + const rcn = (await relColOptions.getParentColumn()).column_name; + const cn = (await relColOptions.getChildColumn()).column_name; + const childTable = await (await relColOptions.getParentColumn()).getModel(); + const parentTable = await (await relColOptions.getChildColumn()).getModel(); + await parentTable.getColumns(); - const childTn = this.getTnPath(childTable) - const parentTn = this.getTnPath(parentTable) + const childTn = this.getTnPath(childTable); + const parentTn = this.getTnPath(parentTable); - const rtn = childTn + const rtn = childTn; const qb = this.dbDriver(rtn) .join(vtn, `${vtn}.${vrcn}`, `${rtn}.${rcn}`) @@ -949,11 +949,11 @@ class BaseModelSqlv2 { // .where(parentTable.primaryKey.cn, id) .where(_wherePk(parentTable.primaryKeys, parentId)), ) - .first() + .first(); - const { count } = await qb + const { count } = await qb; - return count + return count; } // todo: naming & optimizing @@ -961,27 +961,27 @@ class BaseModelSqlv2 { { colId, pid = null }, args, ): Promise { - const { where } = this._getListArgs(args as any) + const { where } = this._getListArgs(args as any); const relColumn = (await this.model.getColumns()).find( (c) => c.id === colId, - ) + ); const relColOptions = - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn - - const mmTable = await relColOptions.getMMModel() - const vtn = this.getTnPath(mmTable) - const vcn = (await relColOptions.getMMChildColumn()).column_name - const vrcn = (await relColOptions.getMMParentColumn()).column_name - const rcn = (await relColOptions.getParentColumn()).column_name - const cn = (await relColOptions.getChildColumn()).column_name - const childTable = await (await relColOptions.getParentColumn()).getModel() - const parentTable = await (await relColOptions.getChildColumn()).getModel() - await parentTable.getColumns() - - const childTn = this.getTnPath(childTable) - const parentTn = this.getTnPath(parentTable) - - const rtn = childTn + (await relColumn.getColOptions()) as LinkToAnotherRecordColumn; + + const mmTable = await relColOptions.getMMModel(); + const vtn = this.getTnPath(mmTable); + const vcn = (await relColOptions.getMMChildColumn()).column_name; + const vrcn = (await relColOptions.getMMParentColumn()).column_name; + const rcn = (await relColOptions.getParentColumn()).column_name; + const cn = (await relColOptions.getChildColumn()).column_name; + const childTable = await (await relColOptions.getParentColumn()).getModel(); + const parentTable = await (await relColOptions.getChildColumn()).getModel(); + await parentTable.getColumns(); + + const childTn = this.getTnPath(childTable); + const parentTn = this.getTnPath(parentTable); + + const rtn = childTn; const qb = this.dbDriver(rtn) .count(`*`, { as: 'count' }) .where((qb) => { @@ -997,14 +997,14 @@ class BaseModelSqlv2 { // .where(parentTable.primaryKey.cn, pid) .where(_wherePk(parentTable.primaryKeys, pid)), ), - ).orWhereNull(rcn) - }) + ).orWhereNull(rcn); + }); - const aliasColObjMap = await childTable.getAliasColObjMap() - const filterObj = extractFilterFromXwhere(where, aliasColObjMap) + const aliasColObjMap = await childTable.getAliasColObjMap(); + const filterObj = extractFilterFromXwhere(where, aliasColObjMap); - await conditionV2(filterObj, qb, this.dbDriver) - return (await qb.first())?.count + await conditionV2(filterObj, qb, this.dbDriver); + return (await qb.first())?.count; } // todo: naming & optimizing @@ -1012,31 +1012,31 @@ class BaseModelSqlv2 { { colId, pid = null }, args, ): Promise { - const { where, ...rest } = this._getListArgs(args as any) + const { where, ...rest } = this._getListArgs(args as any); const relColumn = (await this.model.getColumns()).find( (c) => c.id === colId, - ) + ); const relColOptions = - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn - - const mmTable = await relColOptions.getMMModel() - const vtn = this.getTnPath(mmTable) - const vcn = (await relColOptions.getMMChildColumn()).column_name - const vrcn = (await relColOptions.getMMParentColumn()).column_name - const rcn = (await relColOptions.getParentColumn()).column_name - const cn = (await relColOptions.getChildColumn()).column_name - const childTable = await (await relColOptions.getParentColumn()).getModel() + (await relColumn.getColOptions()) as LinkToAnotherRecordColumn; + + const mmTable = await relColOptions.getMMModel(); + const vtn = this.getTnPath(mmTable); + const vcn = (await relColOptions.getMMChildColumn()).column_name; + const vrcn = (await relColOptions.getMMParentColumn()).column_name; + const rcn = (await relColOptions.getParentColumn()).column_name; + const cn = (await relColOptions.getChildColumn()).column_name; + const childTable = await (await relColOptions.getParentColumn()).getModel(); const childModel = await Model.getBaseModelSQL({ dbDriver: this.dbDriver, model: childTable, - }) - const parentTable = await (await relColOptions.getChildColumn()).getModel() - await parentTable.getColumns() + }); + const parentTable = await (await relColOptions.getChildColumn()).getModel(); + await parentTable.getColumns(); - const childTn = this.getTnPath(childTable) - const parentTn = this.getTnPath(parentTable) + const childTn = this.getTnPath(childTable); + const parentTn = this.getTnPath(parentTable); - const rtn = childTn + const rtn = childTn; const qb = this.dbDriver(rtn).where((qb) => qb @@ -1054,34 +1054,34 @@ class BaseModelSqlv2 { ), ) .orWhereNull(rcn), - ) + ); if (+rest?.shuffle) { - await this.shuffle({ qb }) + await this.shuffle({ qb }); } - await childModel.selectObject({ qb }) + await childModel.selectObject({ qb }); - const aliasColObjMap = await childTable.getAliasColObjMap() - const filterObj = extractFilterFromXwhere(where, aliasColObjMap) - await conditionV2(filterObj, qb, this.dbDriver) + const aliasColObjMap = await childTable.getAliasColObjMap(); + const filterObj = extractFilterFromXwhere(where, aliasColObjMap); + await conditionV2(filterObj, qb, this.dbDriver); // sort by primary key if not autogenerated string // if autogenerated string sort by created_at column if present if (childTable.primaryKey && childTable.primaryKey.ai) { - qb.orderBy(childTable.primaryKey.column_name) + qb.orderBy(childTable.primaryKey.column_name); } else if (childTable.columns.find((c) => c.column_name === 'created_at')) { - qb.orderBy('created_at') + qb.orderBy('created_at'); } - applyPaginate(qb, rest) + applyPaginate(qb, rest); - const proto = await childModel.getProto() - const data = await qb + const proto = await childModel.getProto(); + const data = await qb; return data.map((c) => { - c.__proto__ = proto - return c - }) + c.__proto__ = proto; + return c; + }); } // todo: naming & optimizing @@ -1089,26 +1089,26 @@ class BaseModelSqlv2 { { colId, pid = null }, args, ): Promise { - const { where } = this._getListArgs(args as any) + const { where } = this._getListArgs(args as any); const relColumn = (await this.model.getColumns()).find( (c) => c.id === colId, - ) + ); const relColOptions = - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn + (await relColumn.getColOptions()) as LinkToAnotherRecordColumn; - const cn = (await relColOptions.getChildColumn()).column_name - const rcn = (await relColOptions.getParentColumn()).column_name - const childTable = await (await relColOptions.getChildColumn()).getModel() + const cn = (await relColOptions.getChildColumn()).column_name; + const rcn = (await relColOptions.getParentColumn()).column_name; + const childTable = await (await relColOptions.getChildColumn()).getModel(); const parentTable = await ( await relColOptions.getParentColumn() - ).getModel() + ).getModel(); - const childTn = this.getTnPath(childTable) - const parentTn = this.getTnPath(parentTable) + const childTn = this.getTnPath(childTable); + const parentTn = this.getTnPath(parentTable); - const tn = childTn - const rtn = parentTn - await parentTable.getColumns() + const tn = childTn; + const rtn = parentTn; + await parentTable.getColumns(); const qb = this.dbDriver(tn) .count(`*`, { as: 'count' }) @@ -1119,15 +1119,15 @@ class BaseModelSqlv2 { .select(rcn) // .where(parentTable.primaryKey.cn, pid) .where(_wherePk(parentTable.primaryKeys, pid)), - ).orWhereNull(cn) - }) + ).orWhereNull(cn); + }); - const aliasColObjMap = await childTable.getAliasColObjMap() - const filterObj = extractFilterFromXwhere(where, aliasColObjMap) + const aliasColObjMap = await childTable.getAliasColObjMap(); + const filterObj = extractFilterFromXwhere(where, aliasColObjMap); - await conditionV2(filterObj, qb, this.dbDriver) + await conditionV2(filterObj, qb, this.dbDriver); - return (await qb.first())?.count + return (await qb.first())?.count; } // todo: naming & optimizing @@ -1135,30 +1135,30 @@ class BaseModelSqlv2 { { colId, pid = null }, args, ): Promise { - const { where, ...rest } = this._getListArgs(args as any) + const { where, ...rest } = this._getListArgs(args as any); const relColumn = (await this.model.getColumns()).find( (c) => c.id === colId, - ) + ); const relColOptions = - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn + (await relColumn.getColOptions()) as LinkToAnotherRecordColumn; - const cn = (await relColOptions.getChildColumn()).column_name - const rcn = (await relColOptions.getParentColumn()).column_name - const childTable = await (await relColOptions.getChildColumn()).getModel() + const cn = (await relColOptions.getChildColumn()).column_name; + const rcn = (await relColOptions.getParentColumn()).column_name; + const childTable = await (await relColOptions.getChildColumn()).getModel(); const parentTable = await ( await relColOptions.getParentColumn() - ).getModel() + ).getModel(); const childModel = await Model.getBaseModelSQL({ dbDriver: this.dbDriver, model: childTable, - }) - await parentTable.getColumns() + }); + await parentTable.getColumns(); - const childTn = this.getTnPath(childTable) - const parentTn = this.getTnPath(parentTable) + const childTn = this.getTnPath(childTable); + const parentTn = this.getTnPath(parentTable); - const tn = childTn - const rtn = parentTn + const tn = childTn; + const rtn = parentTn; const qb = this.dbDriver(tn).where((qb) => { qb.whereNotIn( @@ -1167,36 +1167,36 @@ class BaseModelSqlv2 { .select(rcn) // .where(parentTable.primaryKey.cn, pid) .where(_wherePk(parentTable.primaryKeys, pid)), - ).orWhereNull(cn) - }) + ).orWhereNull(cn); + }); if (+rest?.shuffle) { - await this.shuffle({ qb }) + await this.shuffle({ qb }); } - await childModel.selectObject({ qb }) + await childModel.selectObject({ qb }); - const aliasColObjMap = await childTable.getAliasColObjMap() - const filterObj = extractFilterFromXwhere(where, aliasColObjMap) - await conditionV2(filterObj, qb, this.dbDriver) + const aliasColObjMap = await childTable.getAliasColObjMap(); + const filterObj = extractFilterFromXwhere(where, aliasColObjMap); + await conditionV2(filterObj, qb, this.dbDriver); // sort by primary key if not autogenerated string // if autogenerated string sort by created_at column if present if (childTable.primaryKey && childTable.primaryKey.ai) { - qb.orderBy(childTable.primaryKey.column_name) + qb.orderBy(childTable.primaryKey.column_name); } else if (childTable.columns.find((c) => c.column_name === 'created_at')) { - qb.orderBy('created_at') + qb.orderBy('created_at'); } - applyPaginate(qb, rest) + applyPaginate(qb, rest); - const proto = await childModel.getProto() - const data = await this.execAndParse(qb, childTable) + const proto = await childModel.getProto(); + const data = await this.execAndParse(qb, childTable); return data.map((c) => { - c.__proto__ = proto - return c - }) + c.__proto__ = proto; + return c; + }); } // todo: naming & optimizing @@ -1204,26 +1204,26 @@ class BaseModelSqlv2 { { colId, cid = null }, args, ): Promise { - const { where } = this._getListArgs(args as any) + const { where } = this._getListArgs(args as any); const relColumn = (await this.model.getColumns()).find( (c) => c.id === colId, - ) + ); const relColOptions = - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn + (await relColumn.getColOptions()) as LinkToAnotherRecordColumn; - const rcn = (await relColOptions.getParentColumn()).column_name + const rcn = (await relColOptions.getParentColumn()).column_name; const parentTable = await ( await relColOptions.getParentColumn() - ).getModel() - const cn = (await relColOptions.getChildColumn()).column_name - const childTable = await (await relColOptions.getChildColumn()).getModel() + ).getModel(); + const cn = (await relColOptions.getChildColumn()).column_name; + const childTable = await (await relColOptions.getChildColumn()).getModel(); - const childTn = this.getTnPath(childTable) - const parentTn = this.getTnPath(parentTable) + const childTn = this.getTnPath(childTable); + const parentTn = this.getTnPath(parentTable); - const rtn = parentTn - const tn = childTn - await childTable.getColumns() + const rtn = parentTn; + const tn = childTn; + await childTable.getColumns(); const qb = this.dbDriver(rtn) .where((qb) => { @@ -1234,15 +1234,15 @@ class BaseModelSqlv2 { // .where(childTable.primaryKey.cn, cid) .where(_wherePk(childTable.primaryKeys, cid)) .whereNotNull(cn), - ) + ); }) - .count(`*`, { as: 'count' }) + .count(`*`, { as: 'count' }); - const aliasColObjMap = await parentTable.getAliasColObjMap() - const filterObj = extractFilterFromXwhere(where, aliasColObjMap) + const aliasColObjMap = await parentTable.getAliasColObjMap(); + const filterObj = extractFilterFromXwhere(where, aliasColObjMap); - await conditionV2(filterObj, qb, this.dbDriver) - return (await qb.first())?.count + await conditionV2(filterObj, qb, this.dbDriver); + return (await qb.first())?.count; } // todo: naming & optimizing @@ -1250,30 +1250,30 @@ class BaseModelSqlv2 { { colId, cid = null }, args, ): Promise { - const { where, ...rest } = this._getListArgs(args as any) + const { where, ...rest } = this._getListArgs(args as any); const relColumn = (await this.model.getColumns()).find( (c) => c.id === colId, - ) + ); const relColOptions = - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn + (await relColumn.getColOptions()) as LinkToAnotherRecordColumn; - const rcn = (await relColOptions.getParentColumn()).column_name + const rcn = (await relColOptions.getParentColumn()).column_name; const parentTable = await ( await relColOptions.getParentColumn() - ).getModel() - const cn = (await relColOptions.getChildColumn()).column_name - const childTable = await (await relColOptions.getChildColumn()).getModel() + ).getModel(); + const cn = (await relColOptions.getChildColumn()).column_name; + const childTable = await (await relColOptions.getChildColumn()).getModel(); const parentModel = await Model.getBaseModelSQL({ dbDriver: this.dbDriver, model: parentTable, - }) + }); - const childTn = this.getTnPath(childTable) - const parentTn = this.getTnPath(parentTable) + const childTn = this.getTnPath(childTable); + const parentTn = this.getTnPath(parentTable); - const rtn = parentTn - const tn = childTn - await childTable.getColumns() + const rtn = parentTn; + const tn = childTn; + await childTable.getColumns(); const qb = this.dbDriver(rtn).where((qb) => { qb.whereNotIn( @@ -1283,38 +1283,38 @@ class BaseModelSqlv2 { // .where(childTable.primaryKey.cn, cid) .where(_wherePk(childTable.primaryKeys, cid)) .whereNotNull(cn), - ).orWhereNull(rcn) - }) + ).orWhereNull(rcn); + }); if (+rest?.shuffle) { - await this.shuffle({ qb }) + await this.shuffle({ qb }); } - await parentModel.selectObject({ qb }) + await parentModel.selectObject({ qb }); - const aliasColObjMap = await parentTable.getAliasColObjMap() - const filterObj = extractFilterFromXwhere(where, aliasColObjMap) - await conditionV2(filterObj, qb, this.dbDriver) + const aliasColObjMap = await parentTable.getAliasColObjMap(); + const filterObj = extractFilterFromXwhere(where, aliasColObjMap); + await conditionV2(filterObj, qb, this.dbDriver); // sort by primary key if not autogenerated string // if autogenerated string sort by created_at column if present if (parentTable.primaryKey && parentTable.primaryKey.ai) { - qb.orderBy(parentTable.primaryKey.column_name) + qb.orderBy(parentTable.primaryKey.column_name); } else if ( parentTable.columns.find((c) => c.column_name === 'created_at') ) { - qb.orderBy('created_at') + qb.orderBy('created_at'); } - applyPaginate(qb, rest) + applyPaginate(qb, rest); - const proto = await parentModel.getProto() - const data = await this.execAndParse(qb, childTable) + const proto = await parentModel.getProto(); + const data = await this.execAndParse(qb, childTable); return data.map((c) => { - c.__proto__ = proto - return c - }) + c.__proto__ = proto; + return c; + }); } private async getSelectQueryBuilderForFormula( @@ -1323,8 +1323,8 @@ class BaseModelSqlv2 { validateFormula = false, aliasToColumnBuilder = {}, ) { - const formula = await column.getColOptions() - if (formula.error) throw new Error(`Formula error: ${formula.error}`) + const formula = await column.getColOptions(); + if (formula.error) throw new Error(`Formula error: ${formula.error}`); const qb = await formulaQueryBuilderv2( formula.formula, null, @@ -1334,207 +1334,210 @@ class BaseModelSqlv2 { aliasToColumnBuilder, tableAlias, validateFormula, - ) - return qb + ); + return qb; } async getProto() { if (this._proto) { - return this._proto + return this._proto; } - const proto: any = { __columnAliases: {} } - const columns = await this.model.getColumns() + const proto: any = { __columnAliases: {} }; + const columns = await this.model.getColumns(); for (const column of columns) { switch (column.uidt) { - case UITypes.Rollup: { - // @ts-ignore - const colOptions: RollupColumn = await column.getColOptions() - } - break - case UITypes.Lookup: { - // @ts-ignore - const colOptions: LookupColumn = await column.getColOptions() - proto.__columnAliases[column.title] = { - path: [ - (await Column.get({ colId: colOptions.fk_relation_column_id })) - ?.title, - (await Column.get({ colId: colOptions.fk_lookup_column_id })) - ?.title, - ], + case UITypes.Rollup: + { + // @ts-ignore + const colOptions: RollupColumn = await column.getColOptions(); } - } - break - case UITypes.LinkToAnotherRecord: { - this._columns[column.title] = column - const colOptions = - (await column.getColOptions()) as LinkToAnotherRecordColumn - // const parentColumn = await colOptions.getParentColumn(); - - if (colOptions?.type === 'hm') { - const listLoader = new DataLoader(async (ids: string[]) => { - try { - if (ids.length > 1) { - const data = await this.multipleHmList( - { - colId: column.id, - ids, - }, - (listLoader as any).args, - ) - return ids.map((id: string) => (data[id] ? data[id] : [])) - } else { - return [ - await this.hmList( + break; + case UITypes.Lookup: + { + // @ts-ignore + const colOptions: LookupColumn = await column.getColOptions(); + proto.__columnAliases[column.title] = { + path: [ + (await Column.get({ colId: colOptions.fk_relation_column_id })) + ?.title, + (await Column.get({ colId: colOptions.fk_lookup_column_id })) + ?.title, + ], + }; + } + break; + case UITypes.LinkToAnotherRecord: + { + this._columns[column.title] = column; + const colOptions = + (await column.getColOptions()) as LinkToAnotherRecordColumn; + // const parentColumn = await colOptions.getParentColumn(); + + if (colOptions?.type === 'hm') { + const listLoader = new DataLoader(async (ids: string[]) => { + try { + if (ids.length > 1) { + const data = await this.multipleHmList( { colId: column.id, - id: ids[0], + ids, }, (listLoader as any).args, - ), - ] + ); + return ids.map((id: string) => (data[id] ? data[id] : [])); + } else { + return [ + await this.hmList( + { + colId: column.id, + id: ids[0], + }, + (listLoader as any).args, + ), + ]; + } + } catch (e) { + console.log(e); + return []; } - } catch (e) { - console.log(e) - return [] - } - }) - const self: BaseModelSqlv2 = this - - proto[column.title] = async function(args): Promise { - (listLoader as any).args = args - return listLoader.load( - getCompositePk(self.model.primaryKeys, this), - ) - } - - // defining HasMany count method within GQL Type class - // Object.defineProperty(type.prototype, column.alias, { - // async value(): Promise { - // return listLoader.load(this[model.pk.alias]); - // }, - // configurable: true - // }); - } else if (colOptions.type === 'mm') { - const listLoader = new DataLoader(async (ids: string[]) => { - try { - if (ids?.length > 1) { - const data = await this.multipleMmList( - { - parentIds: ids, - colId: column.id, - }, - (listLoader as any).args, - ) - - return data - } else { - return [ - await this.mmList( + }); + const self: BaseModelSqlv2 = this; + + proto[column.title] = async function (args): Promise { + (listLoader as any).args = args; + return listLoader.load( + getCompositePk(self.model.primaryKeys, this), + ); + }; + + // defining HasMany count method within GQL Type class + // Object.defineProperty(type.prototype, column.alias, { + // async value(): Promise { + // return listLoader.load(this[model.pk.alias]); + // }, + // configurable: true + // }); + } else if (colOptions.type === 'mm') { + const listLoader = new DataLoader(async (ids: string[]) => { + try { + if (ids?.length > 1) { + const data = await this.multipleMmList( { - parentId: ids[0], + parentIds: ids, colId: column.id, }, (listLoader as any).args, - ), - ] + ); + + return data; + } else { + return [ + await this.mmList( + { + parentId: ids[0], + colId: column.id, + }, + (listLoader as any).args, + ), + ]; + } + } catch (e) { + console.log(e); + return []; } - } catch (e) { - console.log(e) - return [] - } - }) + }); + + const self: BaseModelSqlv2 = this; + // const childColumn = await colOptions.getChildColumn(); + proto[column.title] = async function (args): Promise { + (listLoader as any).args = args; + return await listLoader.load( + getCompositePk(self.model.primaryKeys, this), + ); + }; + } else if (colOptions.type === 'bt') { + // @ts-ignore + const colOptions = + (await column.getColOptions()) as LinkToAnotherRecordColumn; + const pCol = await Column.get({ + colId: colOptions.fk_parent_column_id, + }); + const cCol = await Column.get({ + colId: colOptions.fk_child_column_id, + }); + const readLoader = new DataLoader(async (ids: string[]) => { + try { + const data = await ( + await Model.getBaseModelSQL({ + id: pCol.fk_model_id, + dbDriver: this.dbDriver, + }) + ).list( + { + // limit: ids.length, + where: `(${pCol.column_name},in,${ids.join(',')})`, + fieldsSet: (readLoader as any).args?.fieldsSet, + }, + true, + ); + const gs = groupBy(data, pCol.title); + return ids.map(async (id: string) => gs?.[id]?.[0]); + } catch (e) { + console.log(e); + return []; + } + }); - const self: BaseModelSqlv2 = this - // const childColumn = await colOptions.getChildColumn(); - proto[column.title] = async function(args): Promise { - (listLoader as any).args = args - return await listLoader.load( - getCompositePk(self.model.primaryKeys, this), - ) - } - } else if (colOptions.type === 'bt') { - // @ts-ignore - const colOptions = - (await column.getColOptions()) as LinkToAnotherRecordColumn - const pCol = await Column.get({ - colId: colOptions.fk_parent_column_id, - }) - const cCol = await Column.get({ - colId: colOptions.fk_child_column_id, - }) - const readLoader = new DataLoader(async (ids: string[]) => { - try { - const data = await ( - await Model.getBaseModelSQL({ - id: pCol.fk_model_id, - dbDriver: this.dbDriver, - }) - ).list( - { - // limit: ids.length, - where: `(${pCol.column_name},in,${ids.join(',')})`, - fieldsSet: (readLoader as any).args?.fieldsSet, - }, - true, + // defining HasMany count method within GQL Type class + proto[column.title] = async function (args?: any) { + if ( + this?.[cCol?.title] === null || + this?.[cCol?.title] === undefined ) - const gs = groupBy(data, pCol.title) - return ids.map(async (id: string) => gs?.[id]?.[0]) - } catch (e) { - console.log(e) - return [] - } - }) - - // defining HasMany count method within GQL Type class - proto[column.title] = async function(args?: any) { - if ( - this?.[cCol?.title] === null || - this?.[cCol?.title] === undefined - ) - return null; + return null; - (readLoader as any).args = args + (readLoader as any).args = args; - return await readLoader.load(this?.[cCol?.title]) + return await readLoader.load(this?.[cCol?.title]); + }; + // todo : handle mm } - // todo : handle mm } - } - break + break; } } - this._proto = proto - return proto + this._proto = proto; + return proto; } _getListArgs(args: XcFilterWithAlias): XcFilter { - const obj: XcFilter = {} - obj.where = args.filter || args.where || args.w || '' - obj.having = args.having || args.h || '' - obj.shuffle = args.shuffle || args.r || '' - obj.condition = args.condition || args.c || {} - obj.conditionGraph = args.conditionGraph || {} + const obj: XcFilter = {}; + obj.where = args.filter || args.where || args.w || ''; + obj.having = args.having || args.h || ''; + obj.shuffle = args.shuffle || args.r || ''; + obj.condition = args.condition || args.c || {}; + obj.conditionGraph = args.conditionGraph || {}; obj.limit = Math.max( Math.min( args.limit || args.l || this.config.limitDefault, this.config.limitMax, ), this.config.limitMin, - ) - obj.offset = Math.max(+(args.offset || args.o) || 0, 0) - obj.fields = args.fields || args.f - obj.sort = args.sort || args.s - return obj + ); + obj.offset = Math.max(+(args.offset || args.o) || 0, 0); + obj.fields = args.fields || args.f; + obj.sort = args.sort || args.s; + return obj; } public async shuffle({ qb }: { qb: Knex.QueryBuilder }): Promise { if (this.isMySQL) { - qb.orderByRaw('RAND()') + qb.orderByRaw('RAND()'); } else if (this.isPg || this.isSqlite) { - qb.orderByRaw('RANDOM()') + qb.orderByRaw('RANDOM()'); } else if (this.isMssql) { - qb.orderByRaw('NEWID()') + qb.orderByRaw('NEWID()'); } } @@ -1542,15 +1545,15 @@ class BaseModelSqlv2 { // pass view id as argument // add option to get only pk and pv public async selectObject({ - qb, - columns: _columns, - fields: _fields, - extractPkAndPv, - viewId, - fieldsSet, - alias, - validateFormula, - }: { + qb, + columns: _columns, + fields: _fields, + extractPkAndPv, + viewId, + fieldsSet, + alias, + validateFormula, + }: { fieldsSet?: Set; qb: Knex.QueryBuilder & Knex.QueryInterface; columns?: Column[]; @@ -1561,32 +1564,32 @@ class BaseModelSqlv2 { validateFormula?: boolean; }): Promise { // keep a common object for all columns to share across all columns - const aliasToColumnBuilder = {} - let viewOrTableColumns: Column[] | { fk_column_id?: string }[] + const aliasToColumnBuilder = {}; + let viewOrTableColumns: Column[] | { fk_column_id?: string }[]; - const res = {} - let view: View - let fields: string[] + const res = {}; + let view: View; + let fields: string[]; if (fieldsSet?.size) { - viewOrTableColumns = _columns || (await this.model.getColumns()) + viewOrTableColumns = _columns || (await this.model.getColumns()); } else { - view = await View.get(viewId) - const viewColumns = viewId && (await View.getColumns(viewId)) - fields = Array.isArray(_fields) ? _fields : _fields?.split(',') + view = await View.get(viewId); + const viewColumns = viewId && (await View.getColumns(viewId)); + fields = Array.isArray(_fields) ? _fields : _fields?.split(','); // const columns = _columns ?? (await this.model.getColumns()); // for (const column of columns) { viewOrTableColumns = - _columns || viewColumns || (await this.model.getColumns()) + _columns || viewColumns || (await this.model.getColumns()); } for (const viewOrTableColumn of viewOrTableColumns) { const column = viewOrTableColumn instanceof Column ? viewOrTableColumn : await Column.get({ - colId: (viewOrTableColumn as GridViewColumn).fk_column_id, - }) + colId: (viewOrTableColumn as GridViewColumn).fk_column_id, + }); // hide if column marked as hidden in view // of if column is system field and system field is hidden if ( @@ -1598,24 +1601,24 @@ class BaseModelSqlv2 { extractPkAndPv, ) ) { - continue + continue; } - if (!checkColumnRequired(column, fields, extractPkAndPv)) continue + if (!checkColumnRequired(column, fields, extractPkAndPv)) continue; switch (column.uidt) { case 'LinkToAnotherRecord': case 'Lookup': - break + break; case 'QrCode': { - const qrCodeColumn = await column.getColOptions() + const qrCodeColumn = await column.getColOptions(); const qrValueColumn = await Column.get({ colId: qrCodeColumn.fk_qr_value_column_id, - }) + }); // If the referenced value cannot be found: cancel current iteration if (qrValueColumn == null) { - break + break; } switch (qrValueColumn.uidt) { @@ -1626,31 +1629,31 @@ class BaseModelSqlv2 { alias, validateFormula, aliasToColumnBuilder, - ) + ); qb.select({ [column.column_name]: selectQb.builder, - }) + }); } catch { - continue + continue; } - break + break; default: { - qb.select({ [column.column_name]: qrValueColumn.column_name }) - break + qb.select({ [column.column_name]: qrValueColumn.column_name }); + break; } } - break + break; } case 'Barcode': { - const barcodeColumn = await column.getColOptions() + const barcodeColumn = await column.getColOptions(); const barcodeValueColumn = await Column.get({ colId: barcodeColumn.fk_barcode_value_column_id, - }) + }); // If the referenced value cannot be found: cancel current iteration if (barcodeValueColumn == null) { - break + break; } switch (barcodeValueColumn.uidt) { @@ -1661,47 +1664,48 @@ class BaseModelSqlv2 { alias, validateFormula, aliasToColumnBuilder, - ) + ); qb.select({ [column.column_name]: selectQb.builder, - }) + }); } catch { - continue + continue; } - break + break; default: { qb.select({ [column.column_name]: barcodeValueColumn.column_name, - }) - break + }); + break; } } - break + break; } - case 'Formula': { - try { - const selectQb = await this.getSelectQueryBuilderForFormula( - column, - alias, - validateFormula, - aliasToColumnBuilder, - ) - qb.select( - this.dbDriver.raw(`?? as ??`, [ - selectQb.builder, - sanitize(column.title), - ]), - ) - } catch (e) { - console.log(e) - // return dummy select - qb.select( - this.dbDriver.raw(`'ERR' as ??`, [sanitize(column.title)]), - ) + case 'Formula': + { + try { + const selectQb = await this.getSelectQueryBuilderForFormula( + column, + alias, + validateFormula, + aliasToColumnBuilder, + ); + qb.select( + this.dbDriver.raw(`?? as ??`, [ + selectQb.builder, + sanitize(column.title), + ]), + ); + } catch (e) { + console.log(e); + // return dummy select + qb.select( + this.dbDriver.raw(`'ERR' as ??`, [sanitize(column.title)]), + ); + } } - } - break + break; case 'Rollup': qb.select( ( @@ -1713,62 +1717,62 @@ class BaseModelSqlv2 { columnOptions: (await column.getColOptions()) as RollupColumn, }) ).builder.as(sanitize(column.title)), - ) - break + ); + break; default: res[sanitize(column.title || column.column_name)] = sanitize( `${alias || this.model.table_name}.${column.column_name}`, - ) - break + ); + break; } } - qb.select(res) + qb.select(res); } async insert(data, trx?, cookie?) { try { - await populatePk(this.model, data) + await populatePk(this.model, data); // todo: filter based on view - const insertObj = await this.model.mapAliasToColumn(data) + const insertObj = await this.model.mapAliasToColumn(data); - await this.validate(insertObj) + await this.validate(insertObj); if ('beforeInsert' in this) { - await this.beforeInsert(insertObj, trx, cookie) + await this.beforeInsert(insertObj, trx, cookie); } - await this.model.getColumns() - let response + await this.model.getColumns(); + let response; // const driver = trx ? trx : this.dbDriver; - const query = this.dbDriver(this.tnPath).insert(insertObj) + const query = this.dbDriver(this.tnPath).insert(insertObj); if ((this.isPg || this.isMssql) && this.model.primaryKey) { query.returning( `${this.model.primaryKey.column_name} as ${this.model.primaryKey.title}`, - ) - response = await this.execAndParse(query) + ); + response = await this.execAndParse(query); } - const ai = this.model.columns.find((c) => c.ai) + const ai = this.model.columns.find((c) => c.ai); - let ag: Column - if (!ai) ag = this.model.columns.find((c) => c.meta?.ag) + let ag: Column; + if (!ai) ag = this.model.columns.find((c) => c.meta?.ag); // handle if autogenerated primary key is used if (ag) { - if (!response) await this.execAndParse(query) - response = await this.readByPk(data[ag.title]) + if (!response) await this.execAndParse(query); + response = await this.readByPk(data[ag.title]); } else if ( !response || (typeof response?.[0] !== 'object' && response?.[0] !== null) ) { - let id + let id; if (response?.length) { - id = response[0] + id = response[0]; } else { - const res = await this.execAndParse(query) - id = res?.id ?? res[0]?.insertId + const res = await this.execAndParse(query); + id = res?.id ?? res[0]?.insertId; } if (ai) { @@ -1778,261 +1782,263 @@ class BaseModelSqlv2 { await this.dbDriver(this.tnPath) .select(ai.column_name) .max(ai.column_name, { as: 'id' }) - )[0].id + )[0].id; } else if (this.isSnowflake) { id = ( (await this.dbDriver(this.tnPath).max(ai.column_name, { as: 'id', })) as any - )[0].id + )[0].id; } - response = await this.readByPk(id) + response = await this.readByPk(id); } else { - response = data + response = data; } } else if (ai) { response = await this.readByPk( Array.isArray(response) ? response?.[0]?.[ai.title] : response?.[ai.title], - ) + ); } - await this.afterInsert(response, trx, cookie) - return Array.isArray(response) ? response[0] : response + await this.afterInsert(response, trx, cookie); + return Array.isArray(response) ? response[0] : response; } catch (e) { - console.log(e) - await this.errorInsert(e, data, trx, cookie) - throw e + console.log(e); + await this.errorInsert(e, data, trx, cookie); + throw e; } } async delByPk(id, trx?, cookie?) { try { // retrieve data for handling params in hook - const data = await this.readByPk(id) - await this.beforeDelete(id, trx, cookie) + const data = await this.readByPk(id); + await this.beforeDelete(id, trx, cookie); const response = await this.dbDriver(this.tnPath) .del() - .where(await this._wherePk(id)) - await this.afterDelete(data, trx, cookie) - return response + .where(await this._wherePk(id)); + await this.afterDelete(data, trx, cookie); + return response; } catch (e) { - console.log(e) - await this.errorDelete(e, id, trx, cookie) - throw e + console.log(e); + await this.errorDelete(e, id, trx, cookie); + throw e; } } async hasLTARData(rowId, model: Model): Promise { - const res = [] + const res = []; const LTARColumns = (await model.getColumns()).filter( (c) => c.uidt === UITypes.LinkToAnotherRecord, - ) - let i = 0 + ); + let i = 0; for (const column of LTARColumns) { const colOptions = - (await column.getColOptions()) as LinkToAnotherRecordColumn - const childColumn = await colOptions.getChildColumn() - const parentColumn = await colOptions.getParentColumn() - const childModel = await childColumn.getModel() - await childModel.getColumns() - const parentModel = await parentColumn.getModel() - await parentModel.getColumns() - let cnt = 0 + (await column.getColOptions()) as LinkToAnotherRecordColumn; + const childColumn = await colOptions.getChildColumn(); + const parentColumn = await colOptions.getParentColumn(); + const childModel = await childColumn.getModel(); + await childModel.getColumns(); + const parentModel = await parentColumn.getModel(); + await parentModel.getColumns(); + let cnt = 0; if (colOptions.type === RelationTypes.HAS_MANY) { cnt = +( await this.dbDriver(childModel.table_name) .count(childColumn.column_name, { as: 'cnt' }) .where(childColumn.column_name, rowId) - )[0].cnt + )[0].cnt; } else if (colOptions.type === RelationTypes.MANY_TO_MANY) { - const mmModel = await colOptions.getMMModel() - const mmChildColumn = await colOptions.getMMChildColumn() + const mmModel = await colOptions.getMMModel(); + const mmChildColumn = await colOptions.getMMChildColumn(); cnt = +( await this.dbDriver(mmModel.table_name) .where(`${mmModel.table_name}.${mmChildColumn.column_name}`, rowId) .count(mmChildColumn.column_name, { as: 'cnt' }) - )[0].cnt + )[0].cnt; } if (cnt) { res.push( `${i++ + 1}. ${model.title}.${ column.title } is a LinkToAnotherRecord of ${childModel.title}`, - ) + ); } } - return res + return res; } async updateByPk(id, data, trx?, cookie?) { try { - const updateObj = await this.model.mapAliasToColumn(data) + const updateObj = await this.model.mapAliasToColumn(data); - await this.validate(data) + await this.validate(data); - await this.beforeUpdate(data, trx, cookie) + await this.beforeUpdate(data, trx, cookie); - const prevData = await this.readByPk(id) + const prevData = await this.readByPk(id); const query = this.dbDriver(this.tnPath) .update(updateObj) - .where(await this._wherePk(id)) + .where(await this._wherePk(id)); - await this.execAndParse(query) + await this.execAndParse(query); - const newData = await this.readByPk(id) - await this.afterUpdate(prevData, newData, trx, cookie, updateObj) - return newData + const newData = await this.readByPk(id); + await this.afterUpdate(prevData, newData, trx, cookie, updateObj); + return newData; } catch (e) { - console.log(e) - await this.errorUpdate(e, data, trx, cookie) - throw e + console.log(e); + await this.errorUpdate(e, data, trx, cookie); + throw e; } } async _wherePk(id) { - await this.model.getColumns() - return _wherePk(this.model.primaryKeys, id) + await this.model.getColumns(); + return _wherePk(this.model.primaryKeys, id); } private getTnPath(tb: Model) { - const schema = (this.dbDriver as any).searchPath?.() + const schema = (this.dbDriver as any).searchPath?.(); if (this.isMssql && schema) { - return this.dbDriver.raw('??.??', [schema, tb.table_name]) + return this.dbDriver.raw('??.??', [schema, tb.table_name]); } else if (this.isSnowflake) { return [ this.dbDriver.client.config.connection.database, this.dbDriver.client.config.connection.schema, tb.table_name, - ].join('.') + ].join('.'); } else { - return tb.table_name + return tb.table_name; } } public get tnPath() { - return this.getTnPath(this.model) + return this.getTnPath(this.model); } get isSqlite() { - return this.clientType === 'sqlite3' + return this.clientType === 'sqlite3'; } get isMssql() { - return this.clientType === 'mssql' + return this.clientType === 'mssql'; } get isPg() { - return this.clientType === 'pg' + return this.clientType === 'pg'; } get isMySQL() { - return this.clientType === 'mysql2' || this.clientType === 'mysql' + return this.clientType === 'mysql2' || this.clientType === 'mysql'; } get isSnowflake() { - return this.clientType === 'snowflake' + return this.clientType === 'snowflake'; } get clientType() { - return this.dbDriver.clientType() + return this.dbDriver.clientType(); } async nestedInsert(data, _trx = null, cookie?) { // const driver = trx ? trx : await this.dbDriver.transaction(); try { - await populatePk(this.model, data) - const insertObj = await this.model.mapAliasToColumn(data) + await populatePk(this.model, data); + const insertObj = await this.model.mapAliasToColumn(data); - let rowId = null - const postInsertOps = [] + let rowId = null; + const postInsertOps = []; const nestedCols = (await this.model.getColumns()).filter( (c) => c.uidt === UITypes.LinkToAnotherRecord, - ) + ); for (const col of nestedCols) { if (col.title in data) { const colOptions = - await col.getColOptions() + await col.getColOptions(); // parse data if it's JSON string const nestedData = typeof data[col.title] === 'string' ? JSON.parse(data[col.title]) - : data[col.title] + : data[col.title]; switch (colOptions.type) { - case RelationTypes.BELONGS_TO: { - const childCol = await colOptions.getChildColumn() - const parentCol = await colOptions.getParentColumn() - insertObj[childCol.column_name] = nestedData?.[parentCol.title] - } - break - case RelationTypes.HAS_MANY: { - const childCol = await colOptions.getChildColumn() - const childModel = await childCol.getModel() - await childModel.getColumns() - - postInsertOps.push(async () => { - await this.dbDriver(childModel.table_name) - .update({ - [childCol.column_name]: rowId, - }) - .whereIn( - childModel.primaryKey.column_name, - nestedData?.map((r) => r[childModel.primaryKey.title]), - ) - }) - } - break + case RelationTypes.BELONGS_TO: + { + const childCol = await colOptions.getChildColumn(); + const parentCol = await colOptions.getParentColumn(); + insertObj[childCol.column_name] = nestedData?.[parentCol.title]; + } + break; + case RelationTypes.HAS_MANY: + { + const childCol = await colOptions.getChildColumn(); + const childModel = await childCol.getModel(); + await childModel.getColumns(); + + postInsertOps.push(async () => { + await this.dbDriver(childModel.table_name) + .update({ + [childCol.column_name]: rowId, + }) + .whereIn( + childModel.primaryKey.column_name, + nestedData?.map((r) => r[childModel.primaryKey.title]), + ); + }); + } + break; case RelationTypes.MANY_TO_MANY: { postInsertOps.push(async () => { const parentModel = await colOptions .getParentColumn() - .then((c) => c.getModel()) - await parentModel.getColumns() - const parentMMCol = await colOptions.getMMParentColumn() - const childMMCol = await colOptions.getMMChildColumn() - const mmModel = await colOptions.getMMModel() + .then((c) => c.getModel()); + await parentModel.getColumns(); + const parentMMCol = await colOptions.getMMParentColumn(); + const childMMCol = await colOptions.getMMChildColumn(); + const mmModel = await colOptions.getMMModel(); const rows = nestedData.map((r) => ({ [parentMMCol.column_name]: r[parentModel.primaryKey.title], [childMMCol.column_name]: rowId, - })) - await this.dbDriver(mmModel.table_name).insert(rows) - }) + })); + await this.dbDriver(mmModel.table_name).insert(rows); + }); } } } } - await this.validate(insertObj) + await this.validate(insertObj); - await this.beforeInsert(insertObj, this.dbDriver, cookie) + await this.beforeInsert(insertObj, this.dbDriver, cookie); - let response - const query = this.dbDriver(this.tnPath).insert(insertObj) + let response; + const query = this.dbDriver(this.tnPath).insert(insertObj); if (this.isPg || this.isMssql) { query.returning( `${this.model.primaryKey.column_name} as ${this.model.primaryKey.title}`, - ) - response = await query + ); + response = await query; } - const ai = this.model.columns.find((c) => c.ai) + const ai = this.model.columns.find((c) => c.ai); if ( !response || (typeof response?.[0] !== 'object' && response?.[0] !== null) ) { - let id + let id; if (response?.length) { - id = response[0] + id = response[0]; } else { - id = (await query)[0] + id = (await query)[0]; } if (ai) { @@ -2042,39 +2048,39 @@ class BaseModelSqlv2 { await this.dbDriver(this.tnPath) .select(ai.column_name) .max(ai.column_name, { as: 'id' }) - )[0].id + )[0].id; } else if (this.isSnowflake) { id = ( (await this.dbDriver(this.tnPath).max(ai.column_name, { as: 'id', })) as any - ).rows[0].id + ).rows[0].id; } - response = await this.readByPk(id) + response = await this.readByPk(id); } else { - response = data + response = data; } } else if (ai) { response = await this.readByPk( Array.isArray(response) ? response?.[0]?.[ai.title] : response?.[ai.title], - ) + ); } - response = Array.isArray(response) ? response[0] : response + response = Array.isArray(response) ? response[0] : response; if (response) rowId = response[this.model.primaryKey.title] || - response[this.model.primaryKey.column_name] + response[this.model.primaryKey.column_name]; - await Promise.all(postInsertOps.map((f) => f())) + await Promise.all(postInsertOps.map((f) => f())); - await this.afterInsert(response, this.dbDriver, cookie) + await this.afterInsert(response, this.dbDriver, cookie); - return response + return response; } catch (e) { - console.log(e) - throw e + console.log(e); + throw e; } } @@ -2092,78 +2098,78 @@ class BaseModelSqlv2 { raw?: boolean; } = {}, ) { - let trx + let trx; try { // TODO: ag column handling for raw bulk insert const insertDatas = raw ? datas : await Promise.all( - datas.map(async (d) => { - await populatePk(this.model, d) - return this.model.mapAliasToColumn(d) - }), - ) + datas.map(async (d) => { + await populatePk(this.model, d); + return this.model.mapAliasToColumn(d); + }), + ); // await this.beforeInsertb(insertDatas, null); if (!raw) { for (const data of datas) { - await this.validate(data) + await this.validate(data); } } // fallbacks to `10` if database client is sqlite // to avoid `too many SQL variables` error // refer : https://www.sqlite.org/limits.html - const chunkSize = this.isSqlite ? 10 : _chunkSize + const chunkSize = this.isSqlite ? 10 : _chunkSize; - trx = await this.dbDriver.transaction() + trx = await this.dbDriver.transaction(); if (!foreign_key_checks) { if (this.isPg) { - await trx.raw('set session_replication_role to replica;') + await trx.raw('set session_replication_role to replica;'); } else if (this.isMySQL) { - await trx.raw('SET foreign_key_checks = 0;') + await trx.raw('SET foreign_key_checks = 0;'); } } - let response + let response; if (this.isSqlite) { // sqlite doesnt support returning, so insert one by one and return ids - response = [] + response = []; for (const insertData of insertDatas) { - const query = trx(this.tnPath).insert(insertData) - const id = (await query)[0] - response.push(await this.readByPk(id)) + const query = trx(this.tnPath).insert(insertData); + const id = (await query)[0]; + response.push(await this.readByPk(id)); } } else { response = this.isPg || this.isMssql ? await trx - .batchInsert(this.tnPath, insertDatas, chunkSize) - .returning(this.model.primaryKey?.column_name) - : await trx.batchInsert(this.tnPath, insertDatas, chunkSize) + .batchInsert(this.tnPath, insertDatas, chunkSize) + .returning(this.model.primaryKey?.column_name) + : await trx.batchInsert(this.tnPath, insertDatas, chunkSize); } if (!foreign_key_checks) { if (this.isPg) { - await trx.raw('set session_replication_role to origin;') + await trx.raw('set session_replication_role to origin;'); } else if (this.isMySQL) { - await trx.raw('SET foreign_key_checks = 1;') + await trx.raw('SET foreign_key_checks = 1;'); } } - await trx.commit() + await trx.commit(); - if (!raw) await this.afterBulkInsert(insertDatas, this.dbDriver, cookie) + if (!raw) await this.afterBulkInsert(insertDatas, this.dbDriver, cookie); - return response + return response; } catch (e) { - await trx?.rollback() + await trx?.rollback(); // await this.errorInsertb(e, data, null); - throw e + throw e; } } @@ -2171,54 +2177,54 @@ class BaseModelSqlv2 { datas: any[], { cookie, raw = false }: { cookie?: any; raw?: boolean } = {}, ) { - let transaction + let transaction; try { - if (raw) await this.model.getColumns() + if (raw) await this.model.getColumns(); const updateDatas = raw ? datas - : await Promise.all(datas.map((d) => this.model.mapAliasToColumn(d))) + : await Promise.all(datas.map((d) => this.model.mapAliasToColumn(d))); - const prevData = [] - const newData = [] - const updatePkValues = [] - const toBeUpdated = [] - const res = [] + const prevData = []; + const newData = []; + const updatePkValues = []; + const toBeUpdated = []; + const res = []; for (const d of updateDatas) { - if (!raw) await this.validate(d) - const pkValues = await this._extractPksValues(d) + if (!raw) await this.validate(d); + const pkValues = await this._extractPksValues(d); if (!pkValues) { // pk not specified - bypass - continue + continue; } - if (!raw) prevData.push(await this.readByPk(pkValues)) - const wherePk = await this._wherePk(pkValues) - res.push(wherePk) - toBeUpdated.push({ d, wherePk }) - updatePkValues.push(pkValues) + if (!raw) prevData.push(await this.readByPk(pkValues)); + const wherePk = await this._wherePk(pkValues); + res.push(wherePk); + toBeUpdated.push({ d, wherePk }); + updatePkValues.push(pkValues); } - transaction = await this.dbDriver.transaction() + transaction = await this.dbDriver.transaction(); for (const o of toBeUpdated) { - await transaction(this.tnPath).update(o.d).where(o.wherePk) + await transaction(this.tnPath).update(o.d).where(o.wherePk); } - await transaction.commit() + await transaction.commit(); if (!raw) { for (const pkValues of updatePkValues) { - newData.push(await this.readByPk(pkValues)) + newData.push(await this.readByPk(pkValues)); } } if (!raw) - await this.afterBulkUpdate(prevData, newData, this.dbDriver, cookie) + await this.afterBulkUpdate(prevData, newData, this.dbDriver, cookie); - return res + return res; } catch (e) { - if (transaction) await transaction.rollback() - throw e + if (transaction) await transaction.rollback(); + throw e; } } @@ -2228,18 +2234,18 @@ class BaseModelSqlv2 { { cookie }: { cookie?: any } = {}, ) { try { - let count = 0 - const updateData = await this.model.mapAliasToColumn(data) - await this.validate(updateData) - const pkValues = await this._extractPksValues(updateData) + let count = 0; + const updateData = await this.model.mapAliasToColumn(data); + await this.validate(updateData); + const pkValues = await this._extractPksValues(updateData); if (pkValues) { // pk is specified - by pass } else { - await this.model.getColumns() - const { where } = this._getListArgs(args) - const qb = this.dbDriver(this.tnPath) - const aliasColObjMap = await this.model.getAliasColObjMap() - const filterObj = extractFilterFromXwhere(where, aliasColObjMap) + await this.model.getColumns(); + const { where } = this._getListArgs(args); + const qb = this.dbDriver(this.tnPath); + const aliasColObjMap = await this.model.getAliasColObjMap(); + const filterObj = extractFilterFromXwhere(where, aliasColObjMap); await conditionV2( [ @@ -2256,55 +2262,55 @@ class BaseModelSqlv2 { ], qb, this.dbDriver, - ) + ); - qb.update(updateData) + qb.update(updateData); - count = (await qb) as any + count = (await qb) as any; } - await this.afterBulkUpdate(null, count, this.dbDriver, cookie, true) + await this.afterBulkUpdate(null, count, this.dbDriver, cookie, true); - return count + return count; } catch (e) { - throw e + throw e; } } async bulkDelete(ids: any[], { cookie }: { cookie?: any } = {}) { - let transaction + let transaction; try { const deleteIds = await Promise.all( ids.map((d) => this.model.mapAliasToColumn(d)), - ) + ); - const deleted = [] - const res = [] + const deleted = []; + const res = []; for (const d of deleteIds) { - const pkValues = await this._extractPksValues(d) + const pkValues = await this._extractPksValues(d); if (!pkValues) { // pk not specified - bypass - continue + continue; } - deleted.push(await this.readByPk(pkValues)) - res.push(d) + deleted.push(await this.readByPk(pkValues)); + res.push(d); } - transaction = await this.dbDriver.transaction() + transaction = await this.dbDriver.transaction(); for (const d of res) { - await transaction(this.tnPath).del().where(d) + await transaction(this.tnPath).del().where(d); } - await transaction.commit() + await transaction.commit(); - await this.afterBulkDelete(deleted, this.dbDriver, cookie) + await this.afterBulkDelete(deleted, this.dbDriver, cookie); - return res + return res; } catch (e) { - if (transaction) await transaction.rollback() - console.log(e) - throw e + if (transaction) await transaction.rollback(); + console.log(e); + throw e; } } @@ -2313,11 +2319,11 @@ class BaseModelSqlv2 { { cookie }: { cookie?: any } = {}, ) { try { - await this.model.getColumns() - const { where } = this._getListArgs(args) - const qb = this.dbDriver(this.tnPath) - const aliasColObjMap = await this.model.getAliasColObjMap() - const filterObj = extractFilterFromXwhere(where, aliasColObjMap) + await this.model.getColumns(); + const { where } = this._getListArgs(args); + const qb = this.dbDriver(this.tnPath); + const aliasColObjMap = await this.model.getAliasColObjMap(); + const filterObj = extractFilterFromXwhere(where, aliasColObjMap); await conditionV2( [ @@ -2334,17 +2340,17 @@ class BaseModelSqlv2 { ], qb, this.dbDriver, - ) + ); - qb.del() + qb.del(); - const count = (await qb) as any + const count = (await qb) as any; - await this.afterBulkDelete(count, this.dbDriver, cookie, true) + await this.afterBulkDelete(count, this.dbDriver, cookie, true); - return count + return count; } catch (e) { - throw e + throw e; } } @@ -2353,12 +2359,12 @@ class BaseModelSqlv2 { * */ public async beforeInsert(data: any, _trx: any, req): Promise { - await this.handleHooks('before.insert', null, data, req) + await this.handleHooks('before.insert', null, data, req); } public async afterInsert(data: any, _trx: any, req): Promise { - await this.handleHooks('after.insert', null, data, req) - const id = this._extractPksValues(data) + await this.handleHooks('after.insert', null, data, req); + const id = this._extractPksValues(data); await Audit.insert({ fk_model_id: this.model.id, row_id: id, @@ -2370,7 +2376,7 @@ class BaseModelSqlv2 { // details: JSON.stringify(data), ip: req?.clientIp, user: req?.user?.email, - }) + }); } public async afterBulkUpdate( @@ -2380,10 +2386,10 @@ class BaseModelSqlv2 { req, isBulkAllOperation = false, ): Promise { - let noOfUpdatedRecords = newData + let noOfUpdatedRecords = newData; if (!isBulkAllOperation) { - noOfUpdatedRecords = newData.length - await this.handleHooks('after.bulkUpdate', prevData, newData, req) + noOfUpdatedRecords = newData.length; + await this.handleHooks('after.bulkUpdate', prevData, newData, req); } await Audit.insert({ @@ -2398,7 +2404,7 @@ class BaseModelSqlv2 { // details: JSON.stringify(data), ip: req?.clientIp, user: req?.user?.email, - }) + }); } public async afterBulkDelete( @@ -2407,10 +2413,10 @@ class BaseModelSqlv2 { req, isBulkAllOperation = false, ): Promise { - let noOfDeletedRecords = data + let noOfDeletedRecords = data; if (!isBulkAllOperation) { - noOfDeletedRecords = data.length - await this.handleHooks('after.bulkDelete', null, data, req) + noOfDeletedRecords = data.length; + await this.handleHooks('after.bulkDelete', null, data, req); } await Audit.insert({ @@ -2425,11 +2431,11 @@ class BaseModelSqlv2 { // details: JSON.stringify(data), ip: req?.clientIp, user: req?.user?.email, - }) + }); } public async afterBulkInsert(data: any[], _trx: any, req): Promise { - await this.handleHooks('after.bulkInsert', null, data, req) + await this.handleHooks('after.bulkInsert', null, data, req); await Audit.insert({ fk_model_id: this.model.id, @@ -2443,18 +2449,18 @@ class BaseModelSqlv2 { // details: JSON.stringify(data), ip: req?.clientIp, user: req?.user?.email, - }) + }); } public async beforeUpdate(data: any, _trx: any, req): Promise { - const ignoreWebhook = req.query?.ignoreWebhook + const ignoreWebhook = req.query?.ignoreWebhook; if (ignoreWebhook) { if (ignoreWebhook != 'true' && ignoreWebhook != 'false') { - throw new Error('ignoreWebhook value can be either true or false') + throw new Error('ignoreWebhook value can be either true or false'); } } if (ignoreWebhook === undefined || ignoreWebhook === 'false') { - await this.handleHooks('before.update', null, data, req) + await this.handleHooks('before.update', null, data, req); } } @@ -2465,25 +2471,25 @@ class BaseModelSqlv2 { req, updateObj?: Record, ): Promise { - const id = this._extractPksValues(newData) - let desc = `Record with ID ${id} has been updated in Table ${this.model.title}.` - let details = '' + const id = this._extractPksValues(newData); + let desc = `Record with ID ${id} has been updated in Table ${this.model.title}.`; + let details = ''; if (updateObj) { - updateObj = await this.model.mapColumnToAlias(updateObj) + updateObj = await this.model.mapColumnToAlias(updateObj); for (const k of Object.keys(updateObj)) { const prevValue = typeof prevData[k] === 'object' ? JSON.stringify(prevData[k]) - : prevData[k] + : prevData[k]; const newValue = typeof newData[k] === 'object' ? JSON.stringify(newData[k]) - : newData[k] - desc += `\n` - desc += `Column "${k}" got changed from "${prevValue}" to "${newValue}"` + : newData[k]; + desc += `\n`; + desc += `Column "${k}" got changed from "${prevValue}" to "${newValue}"`; details += DOMPurify.sanitize(`${k} : ${prevValue} - ${newValue}`) + ${newValue}`); } } await Audit.insert({ @@ -2495,25 +2501,25 @@ class BaseModelSqlv2 { details, ip: req?.clientIp, user: req?.user?.email, - }) + }); - const ignoreWebhook = req.query?.ignoreWebhook + const ignoreWebhook = req.query?.ignoreWebhook; if (ignoreWebhook) { if (ignoreWebhook != 'true' && ignoreWebhook != 'false') { - throw new Error('ignoreWebhook value can be either true or false') + throw new Error('ignoreWebhook value can be either true or false'); } } if (ignoreWebhook === undefined || ignoreWebhook === 'false') { - await this.handleHooks('after.update', prevData, newData, req) + await this.handleHooks('after.update', prevData, newData, req); } } public async beforeDelete(data: any, _trx: any, req): Promise { - await this.handleHooks('before.delete', null, data, req) + await this.handleHooks('before.delete', null, data, req); } public async afterDelete(data: any, _trx: any, req): Promise { - const id = req?.params?.id + const id = req?.params?.id; await Audit.insert({ fk_model_id: this.model.id, row_id: id, @@ -2525,8 +2531,8 @@ class BaseModelSqlv2 { // details: JSON.stringify(data), ip: req?.clientIp, user: req?.user?.email, - }) - await this.handleHooks('after.delete', null, data, req) + }); + await this.handleHooks('after.delete', null, data, req); } private async handleHooks(hookName, prevData, newData, req): Promise { @@ -2538,7 +2544,7 @@ class BaseModelSqlv2 { viewId: this.viewId, modelId: this.model.id, tnPath: this.tnPath, - }) + }); /* const view = await View.get(this.viewId); @@ -2634,52 +2640,49 @@ class BaseModelSqlv2 { } // @ts-ignore - protected async errorInsert(e, data, trx, cookie) { - } + protected async errorInsert(e, data, trx, cookie) {} // @ts-ignore - protected async errorUpdate(e, data, trx, cookie) { - } + protected async errorUpdate(e, data, trx, cookie) {} // todo: handle composite primary key protected _extractPksValues(data: any) { // data can be still inserted without PK // TODO: return a meaningful value - if (!this.model.primaryKey) return 'N/A' + if (!this.model.primaryKey) return 'N/A'; return ( data[this.model.primaryKey.title] || data[this.model.primaryKey.column_name] - ) + ); } // @ts-ignore - protected async errorDelete(e, id, trx, cookie) { - } + protected async errorDelete(e, id, trx, cookie) {} async validate(columns) { - await this.model.getColumns() + await this.model.getColumns(); // let cols = Object.keys(this.columns); for (let i = 0; i < this.model.columns.length; ++i) { - const column = this.model.columns[i] + const column = this.model.columns[i]; // skip validation if `validate` is undefined or false - if (!column?.meta?.validate || !column?.validate) continue + if (!column?.meta?.validate || !column?.validate) continue; - const validate = column.getValidators() - const cn = column.column_name - const columnTitle = column.title - if (!validate) continue + const validate = column.getValidators(); + const cn = column.column_name; + const columnTitle = column.title; + if (!validate) continue; - const { func, msg } = validate + const { func, msg } = validate; for (let j = 0; j < func.length; ++j) { const fn = typeof func[j] === 'string' ? customValidators[func[j]] ? customValidators[func[j]] : Validator[func[j]] - : func[j] - const columnValue = columns?.[cn] || columns?.[columnTitle] + : func[j]; + const columnValue = columns?.[cn] || columns?.[columnTitle]; const arg = - typeof func[j] === 'string' ? columnValue + '' : columnValue + typeof func[j] === 'string' ? columnValue + '' : columnValue; if ( ![null, undefined, ''].includes(columnValue) && !(fn.constructor.name === 'AsyncFunction' ? await fn(arg) : fn(arg)) @@ -2688,112 +2691,115 @@ class BaseModelSqlv2 { msg[j] .replace(/\{VALUE}/g, columnValue) .replace(/\{cn}/g, columnTitle), - ) + ); } } } - return true + return true; } async addChild({ - colId, - rowId, - childId, - cookie, - }: { + colId, + rowId, + childId, + cookie, + }: { colId: string; rowId: string; childId: string; cookie?: any; }) { - const columns = await this.model.getColumns() - const column = columns.find((c) => c.id === colId) + const columns = await this.model.getColumns(); + const column = columns.find((c) => c.id === colId); if (!column || column.uidt !== UITypes.LinkToAnotherRecord) - NcError.notFound('Column not found') + NcError.notFound('Column not found'); - const colOptions = await column.getColOptions() + const colOptions = await column.getColOptions(); - const childColumn = await colOptions.getChildColumn() - const parentColumn = await colOptions.getParentColumn() - const parentTable = await parentColumn.getModel() - const childTable = await childColumn.getModel() - await childTable.getColumns() - await parentTable.getColumns() + const childColumn = await colOptions.getChildColumn(); + const parentColumn = await colOptions.getParentColumn(); + const parentTable = await parentColumn.getModel(); + const childTable = await childColumn.getModel(); + await childTable.getColumns(); + await parentTable.getColumns(); - const childTn = this.getTnPath(childTable) - const parentTn = this.getTnPath(parentTable) + const childTn = this.getTnPath(childTable); + const parentTn = this.getTnPath(parentTable); switch (colOptions.type) { - case RelationTypes.MANY_TO_MANY: { - const vChildCol = await colOptions.getMMChildColumn() - const vParentCol = await colOptions.getMMParentColumn() - const vTable = await colOptions.getMMModel() - - const vTn = this.getTnPath(vTable) - - if (this.isSnowflake) { - const parentPK = this.dbDriver(parentTn) - .select(parentColumn.column_name) - .where(_wherePk(parentTable.primaryKeys, childId)) - .first() + case RelationTypes.MANY_TO_MANY: + { + const vChildCol = await colOptions.getMMChildColumn(); + const vParentCol = await colOptions.getMMParentColumn(); + const vTable = await colOptions.getMMModel(); - const childPK = this.dbDriver(childTn) - .select(childColumn.column_name) - .where(_wherePk(childTable.primaryKeys, rowId)) - .first() + const vTn = this.getTnPath(vTable); - await this.dbDriver.raw( - `INSERT INTO ?? (??, ??) SELECT (${parentPK.toQuery()}), (${childPK.toQuery()})`, - [vTn, vParentCol.column_name, vChildCol.column_name], - ) - } else { - await this.dbDriver(vTn).insert({ - [vParentCol.column_name]: this.dbDriver(parentTn) + if (this.isSnowflake) { + const parentPK = this.dbDriver(parentTn) .select(parentColumn.column_name) .where(_wherePk(parentTable.primaryKeys, childId)) - .first(), - [vChildCol.column_name]: this.dbDriver(childTn) + .first(); + + const childPK = this.dbDriver(childTn) .select(childColumn.column_name) .where(_wherePk(childTable.primaryKeys, rowId)) - .first(), - }) - } - } - break - case RelationTypes.HAS_MANY: { - await this.dbDriver(childTn) - .update({ - [childColumn.column_name]: this.dbDriver.from( - this.dbDriver(parentTn) - .select(parentColumn.column_name) - .where(_wherePk(parentTable.primaryKeys, rowId)) - .first() - .as('___cn_alias'), - ), - }) - .where(_wherePk(childTable.primaryKeys, childId)) - } - break - case RelationTypes.BELONGS_TO: { - await this.dbDriver(childTn) - .update({ - [childColumn.column_name]: this.dbDriver.from( - this.dbDriver(parentTn) + .first(); + + await this.dbDriver.raw( + `INSERT INTO ?? (??, ??) SELECT (${parentPK.toQuery()}), (${childPK.toQuery()})`, + [vTn, vParentCol.column_name, vChildCol.column_name], + ); + } else { + await this.dbDriver(vTn).insert({ + [vParentCol.column_name]: this.dbDriver(parentTn) .select(parentColumn.column_name) .where(_wherePk(parentTable.primaryKeys, childId)) - .first() - .as('___cn_alias'), - ), - }) - .where(_wherePk(childTable.primaryKeys, rowId)) - } - break + .first(), + [vChildCol.column_name]: this.dbDriver(childTn) + .select(childColumn.column_name) + .where(_wherePk(childTable.primaryKeys, rowId)) + .first(), + }); + } + } + break; + case RelationTypes.HAS_MANY: + { + await this.dbDriver(childTn) + .update({ + [childColumn.column_name]: this.dbDriver.from( + this.dbDriver(parentTn) + .select(parentColumn.column_name) + .where(_wherePk(parentTable.primaryKeys, rowId)) + .first() + .as('___cn_alias'), + ), + }) + .where(_wherePk(childTable.primaryKeys, childId)); + } + break; + case RelationTypes.BELONGS_TO: + { + await this.dbDriver(childTn) + .update({ + [childColumn.column_name]: this.dbDriver.from( + this.dbDriver(parentTn) + .select(parentColumn.column_name) + .where(_wherePk(parentTable.primaryKeys, childId)) + .first() + .as('___cn_alias'), + ), + }) + .where(_wherePk(childTable.primaryKeys, rowId)); + } + break; } - const response = await this.readByPk(rowId) - await this.afterInsert(response, this.dbDriver, cookie) - await this.afterAddChild(rowId, childId, cookie) + const response = await this.readByPk(rowId); + await this.afterInsert(response, this.dbDriver, cookie); + await this.afterAddChild(rowId, childId, cookie); } public async afterAddChild(rowId, childId, req): Promise { @@ -2808,91 +2814,94 @@ class BaseModelSqlv2 { // details: JSON.stringify(data), ip: req?.clientIp, user: req?.user?.email, - }) + }); } async removeChild({ - colId, - rowId, - childId, - cookie, - }: { + colId, + rowId, + childId, + cookie, + }: { colId: string; rowId: string; childId: string; cookie?: any; }) { - const columns = await this.model.getColumns() - const column = columns.find((c) => c.id === colId) + const columns = await this.model.getColumns(); + const column = columns.find((c) => c.id === colId); if (!column || column.uidt !== UITypes.LinkToAnotherRecord) - NcError.notFound('Column not found') + NcError.notFound('Column not found'); - const colOptions = await column.getColOptions() + const colOptions = await column.getColOptions(); - const childColumn = await colOptions.getChildColumn() - const parentColumn = await colOptions.getParentColumn() - const parentTable = await parentColumn.getModel() - const childTable = await childColumn.getModel() - await childTable.getColumns() - await parentTable.getColumns() + const childColumn = await colOptions.getChildColumn(); + const parentColumn = await colOptions.getParentColumn(); + const parentTable = await parentColumn.getModel(); + const childTable = await childColumn.getModel(); + await childTable.getColumns(); + await parentTable.getColumns(); - const childTn = this.getTnPath(childTable) - const parentTn = this.getTnPath(parentTable) + const childTn = this.getTnPath(childTable); + const parentTn = this.getTnPath(parentTable); - const prevData = await this.readByPk(rowId) + const prevData = await this.readByPk(rowId); switch (colOptions.type) { - case RelationTypes.MANY_TO_MANY: { - const vChildCol = await colOptions.getMMChildColumn() - const vParentCol = await colOptions.getMMParentColumn() - const vTable = await colOptions.getMMModel() + case RelationTypes.MANY_TO_MANY: + { + const vChildCol = await colOptions.getMMChildColumn(); + const vParentCol = await colOptions.getMMParentColumn(); + const vTable = await colOptions.getMMModel(); - const vTn = this.getTnPath(vTable) + const vTn = this.getTnPath(vTable); - await this.dbDriver(vTn) - .where({ - [vParentCol.column_name]: this.dbDriver(parentTn) - .select(parentColumn.column_name) - .where(_wherePk(parentTable.primaryKeys, childId)) - .first(), - [vChildCol.column_name]: this.dbDriver(childTn) - .select(childColumn.column_name) - .where(_wherePk(childTable.primaryKeys, rowId)) - .first(), - }) - .delete() - } - break - case RelationTypes.HAS_MANY: { - await this.dbDriver(childTn) - // .where({ - // [childColumn.cn]: this.dbDriver(parentTable.tn) - // .select(parentColumn.cn) - // .where(parentTable.primaryKey.cn, rowId) - // .first() - // }) - .where(_wherePk(childTable.primaryKeys, childId)) - .update({ [childColumn.column_name]: null }) - } - break - case RelationTypes.BELONGS_TO: { - await this.dbDriver(childTn) - // .where({ - // [childColumn.cn]: this.dbDriver(parentTable.tn) - // .select(parentColumn.cn) - // .where(parentTable.primaryKey.cn, childId) - // .first() - // }) - .where(_wherePk(childTable.primaryKeys, rowId)) - .update({ [childColumn.column_name]: null }) - } - break + await this.dbDriver(vTn) + .where({ + [vParentCol.column_name]: this.dbDriver(parentTn) + .select(parentColumn.column_name) + .where(_wherePk(parentTable.primaryKeys, childId)) + .first(), + [vChildCol.column_name]: this.dbDriver(childTn) + .select(childColumn.column_name) + .where(_wherePk(childTable.primaryKeys, rowId)) + .first(), + }) + .delete(); + } + break; + case RelationTypes.HAS_MANY: + { + await this.dbDriver(childTn) + // .where({ + // [childColumn.cn]: this.dbDriver(parentTable.tn) + // .select(parentColumn.cn) + // .where(parentTable.primaryKey.cn, rowId) + // .first() + // }) + .where(_wherePk(childTable.primaryKeys, childId)) + .update({ [childColumn.column_name]: null }); + } + break; + case RelationTypes.BELONGS_TO: + { + await this.dbDriver(childTn) + // .where({ + // [childColumn.cn]: this.dbDriver(parentTable.tn) + // .select(parentColumn.cn) + // .where(parentTable.primaryKey.cn, childId) + // .first() + // }) + .where(_wherePk(childTable.primaryKeys, rowId)) + .update({ [childColumn.column_name]: null }); + } + break; } - const newData = await this.readByPk(rowId) - await this.afterUpdate(prevData, newData, this.dbDriver, cookie) - await this.afterRemoveChild(rowId, childId, cookie) + const newData = await this.readByPk(rowId); + await this.afterUpdate(prevData, newData, this.dbDriver, cookie); + await this.afterRemoveChild(rowId, childId, cookie); } public async afterRemoveChild(rowId, childId, req): Promise { @@ -2907,7 +2916,7 @@ class BaseModelSqlv2 { // details: JSON.stringify(data), ip: req?.clientIp, user: req?.user?.email, - }) + }); } public async groupedList( @@ -2916,32 +2925,34 @@ class BaseModelSqlv2 { ignoreViewFilterAndSort?: boolean; options?: (string | number | null | boolean)[]; } & Partial, - ): Promise<{ - key: string; - value: Record[]; - }[]> { + ): Promise< + { + key: string; + value: Record[]; + }[] + > { try { - const { where, ...rest } = this._getListArgs(args as any) + const { where, ...rest } = this._getListArgs(args as any); const column = await this.model .getColumns() - .then((cols) => cols?.find((col) => col.id === args.groupColumnId)) + .then((cols) => cols?.find((col) => col.id === args.groupColumnId)); - if (!column) NcError.notFound('Column not found') + if (!column) NcError.notFound('Column not found'); if (isVirtualCol(column)) - NcError.notImplemented('Grouping for virtual columns not implemented') + NcError.notImplemented('Grouping for virtual columns not implemented'); // extract distinct group column values - let groupingValues: Set + let groupingValues: Set; if (args.options?.length) { - groupingValues = new Set(args.options) + groupingValues = new Set(args.options); } else if (column.uidt === UITypes.SingleSelect) { const colOptions = await column.getColOptions<{ options: SelectOption[]; - }>() + }>(); groupingValues = new Set( (colOptions?.options ?? []).map((opt) => opt.title), - ) - groupingValues.add(null) + ); + groupingValues.add(null); } else { groupingValues = new Set( ( @@ -2949,20 +2960,20 @@ class BaseModelSqlv2 { .select(column.column_name) .distinct() ).map((row) => row[column.column_name]), - ) - groupingValues.add(null) + ); + groupingValues.add(null); } - const qb = this.dbDriver(this.tnPath) - qb.limit(+rest?.limit || 25) - qb.offset(+rest?.offset || 0) + const qb = this.dbDriver(this.tnPath); + qb.limit(+rest?.limit || 25); + qb.offset(+rest?.offset || 0); - await this.selectObject({ qb, extractPkAndPv: true }) + await this.selectObject({ qb, extractPkAndPv: true }); // todo: refactor and move to a method (applyFilterAndSort) - const aliasColObjMap = await this.model.getAliasColObjMap() - let sorts = extractSortsObject(args?.sort, aliasColObjMap) - const filterObj = extractFilterFromXwhere(where, aliasColObjMap) + const aliasColObjMap = await this.model.getAliasColObjMap(); + let sorts = extractSortsObject(args?.sort, aliasColObjMap); + const filterObj = extractFilterFromXwhere(where, aliasColObjMap); // todo: replace with view id if (!args.ignoreViewFilterAndSort && this.viewId) { await conditionV2( @@ -2985,14 +2996,14 @@ class BaseModelSqlv2 { ], qb, this.dbDriver, - ) + ); if (!sorts) sorts = args.sortArr?.length ? args.sortArr - : await Sort.list({ viewId: this.viewId }) + : await Sort.list({ viewId: this.viewId }); - if (sorts?.['length']) await sortV2(sorts, qb, this.dbDriver) + if (sorts?.['length']) await sortV2(sorts, qb, this.dbDriver); } else { await conditionV2( [ @@ -3009,71 +3020,71 @@ class BaseModelSqlv2 { ], qb, this.dbDriver, - ) + ); - if (!sorts) sorts = args.sortArr + if (!sorts) sorts = args.sortArr; - if (sorts?.['length']) await sortV2(sorts, qb, this.dbDriver) + if (sorts?.['length']) await sortV2(sorts, qb, this.dbDriver); } // sort by primary key if not autogenerated string // if autogenerated string sort by created_at column if present if (this.model.primaryKey && this.model.primaryKey.ai) { - qb.orderBy(this.model.primaryKey.column_name) + qb.orderBy(this.model.primaryKey.column_name); } else if ( this.model.columns.find((c) => c.column_name === 'created_at') ) { - qb.orderBy('created_at') + qb.orderBy('created_at'); } const groupedQb = this.dbDriver.from( this.dbDriver .unionAll( [...groupingValues].map((r) => { - const query = qb.clone() + const query = qb.clone(); if (r === null) { - query.whereNull(column.column_name) + query.whereNull(column.column_name); } else { - query.where(column.column_name, r) + query.where(column.column_name, r); } - return this.isSqlite ? this.dbDriver.select().from(query) : query + return this.isSqlite ? this.dbDriver.select().from(query) : query; }), !this.isSqlite, ) .as('__nc_grouped_list'), - ) + ); - const proto = await this.getProto() + const proto = await this.getProto(); - const data = await groupedQb + const data = await groupedQb; const result = data?.map((d) => { - d.__proto__ = proto - return d - }) + d.__proto__ = proto; + return d; + }); const groupedResult = result.reduce>( (aggObj, row) => { if (!aggObj.has(row[column.title])) { - aggObj.set(row[column.title], []) + aggObj.set(row[column.title], []); } - aggObj.get(row[column.title]).push(row) + aggObj.get(row[column.title]).push(row); - return aggObj + return aggObj; }, new Map(), - ) + ); const r = [...groupingValues].map((key) => ({ key, value: groupedResult.get(key) ?? [], - })) + })); - return r + return r; } catch (e) { - console.log(e) - throw e + console.log(e); + throw e; } } @@ -3085,19 +3096,19 @@ class BaseModelSqlv2 { ) { const column = await this.model .getColumns() - .then((cols) => cols?.find((col) => col.id === args.groupColumnId)) + .then((cols) => cols?.find((col) => col.id === args.groupColumnId)); - if (!column) NcError.notFound('Column not found') + if (!column) NcError.notFound('Column not found'); if (isVirtualCol(column)) - NcError.notImplemented('Grouping for virtual columns not implemented') + NcError.notImplemented('Grouping for virtual columns not implemented'); const qb = this.dbDriver(this.tnPath) .count('*', { as: 'count' }) - .groupBy(column.column_name) + .groupBy(column.column_name); // todo: refactor and move to a common method (applyFilterAndSort) - const aliasColObjMap = await this.model.getAliasColObjMap() - const filterObj = extractFilterFromXwhere(args.where, aliasColObjMap) + const aliasColObjMap = await this.model.getAliasColObjMap(); + const filterObj = extractFilterFromXwhere(args.where, aliasColObjMap); // todo: replace with view id if (!args.ignoreViewFilterAndSort && this.viewId) { @@ -3121,7 +3132,7 @@ class BaseModelSqlv2 { ], qb, this.dbDriver, - ) + ); } else { await conditionV2( [ @@ -3138,34 +3149,34 @@ class BaseModelSqlv2 { ], qb, this.dbDriver, - ) + ); } await this.selectObject({ qb, columns: [new Column({ ...column, title: 'key' })], - }) + }); - return await qb + return await qb; } private async execAndParse(qb: Knex.QueryBuilder, childTable?: Model) { - let query = qb.toQuery() + let query = qb.toQuery(); if (!this.isPg && !this.isMssql && !this.isSnowflake) { - query = unsanitize(qb.toQuery()) + query = unsanitize(qb.toQuery()); } else { - query = sanitize(query) + query = sanitize(query); } return this.convertAttachmentType( this.isPg || this.isSnowflake ? (await this.dbDriver.raw(query))?.rows : query.slice(0, 6) === 'select' && !this.isMssql - ? await this.dbDriver.from( + ? await this.dbDriver.from( this.dbDriver.raw(query).wrap('(', ') __nc_alias'), ) - : await this.dbDriver.raw(query), + : await this.dbDriver.raw(query), childTable, - ) + ); } private _convertAttachmentType( @@ -3176,13 +3187,12 @@ class BaseModelSqlv2 { if (d) { attachmentColumns.forEach((col) => { if (d[col.title] && typeof d[col.title] === 'string') { - d[col.title] = JSON.parse(d[col.title]) + d[col.title] = JSON.parse(d[col.title]); } - }) + }); } - } catch { - } - return d + } catch {} + return d; } private convertAttachmentType(data: Record, childTable?: Model) { @@ -3191,18 +3201,18 @@ class BaseModelSqlv2 { if (data) { const attachmentColumns = ( childTable ? childTable.columns : this.model.columns - ).filter((c) => c.uidt === UITypes.Attachment) + ).filter((c) => c.uidt === UITypes.Attachment); if (attachmentColumns.length) { if (Array.isArray(data)) { data = data.map((d) => this._convertAttachmentType(attachmentColumns, d), - ) + ); } else { - this._convertAttachmentType(attachmentColumns, data) + this._convertAttachmentType(attachmentColumns, data); } } } - return data + return data; } } @@ -3210,21 +3220,21 @@ function extractSortsObject( _sorts: string | string[], aliasColObjMap: { [columnAlias: string]: Column }, ): Sort[] | void { - if (!_sorts?.length) return + if (!_sorts?.length) return; - let sorts = _sorts + let sorts = _sorts; - if (!Array.isArray(sorts)) sorts = sorts.split(',') + if (!Array.isArray(sorts)) sorts = sorts.split(','); return sorts.map((s) => { - const sort: SortType = { direction: 'asc' } + const sort: SortType = { direction: 'asc' }; if (s.startsWith('-')) { - sort.direction = 'desc' - sort.fk_column_id = aliasColObjMap[s.slice(1)]?.id - } else sort.fk_column_id = aliasColObjMap[s]?.id + sort.direction = 'desc'; + sort.fk_column_id = aliasColObjMap[s.slice(1)]?.id; + } else sort.fk_column_id = aliasColObjMap[s]?.id; - return new Sort(sort) - }) + return new Sort(sort); + }); } function extractFilterFromXwhere( @@ -3232,26 +3242,26 @@ function extractFilterFromXwhere( aliasColObjMap: { [columnAlias: string]: Column }, ) { if (!str) { - return [] + return []; } - let nestedArrayConditions = [] + let nestedArrayConditions = []; - let openIndex = str.indexOf('((') + let openIndex = str.indexOf('(('); - if (openIndex === -1) openIndex = str.indexOf('(~') + if (openIndex === -1) openIndex = str.indexOf('(~'); - let nextOpenIndex = openIndex + let nextOpenIndex = openIndex; - let closingIndex = str.indexOf('))') + let closingIndex = str.indexOf('))'); // if it's a simple query simply return array of conditions if (openIndex === -1) { if (str && str != '~not') nestedArrayConditions = str.split( /(?=~(?:or(?:not)?|and(?:not)?|not)\()/, - ) - return extractCondition(nestedArrayConditions || [], aliasColObjMap) + ); + return extractCondition(nestedArrayConditions || [], aliasColObjMap); } // iterate until finding right closing @@ -3259,8 +3269,8 @@ function extractFilterFromXwhere( (nextOpenIndex = str .substring(0, closingIndex) .indexOf('((', nextOpenIndex + 1)) != -1 - ) { - closingIndex = str.indexOf('))', closingIndex + 1) + ) { + closingIndex = str.indexOf('))', closingIndex + 1); } if (closingIndex === -1) @@ -3268,15 +3278,15 @@ function extractFilterFromXwhere( `${str .substring(0, openIndex + 1) .slice(-10)} : Closing bracket not found`, - ) + ); // getting operand starting index - const operandStartIndex = str.lastIndexOf('~', openIndex) + const operandStartIndex = str.lastIndexOf('~', openIndex); const operator = operandStartIndex != -1 ? str.substring(operandStartIndex + 1, openIndex) - : '' - const lhsOfNestedQuery = str.substring(0, openIndex) + : ''; + const lhsOfNestedQuery = str.substring(0, openIndex); nestedArrayConditions.push( ...extractFilterFromXwhere(lhsOfNestedQuery, aliasColObjMap), @@ -3291,28 +3301,28 @@ function extractFilterFromXwhere( }), // RHS of nested query(recursion) ...extractFilterFromXwhere(str.substring(closingIndex + 2), aliasColObjMap), - ) - return nestedArrayConditions + ); + return nestedArrayConditions; } // mark `op` and `sub_op` any for being assignable to parameter of type function validateFilterComparison(uidt: UITypes, op: any, sub_op?: any) { if (!COMPARISON_OPS.includes(op)) { - NcError.badRequest(`${op} is not supported.`) + NcError.badRequest(`${op} is not supported.`); } if (sub_op) { if (![UITypes.Date, UITypes.DateTime].includes(uidt)) { - NcError.badRequest(`'${sub_op}' is not supported for UI Type'${uidt}'.`) + NcError.badRequest(`'${sub_op}' is not supported for UI Type'${uidt}'.`); } if (!COMPARISON_SUB_OPS.includes(sub_op)) { - NcError.badRequest(`'${sub_op}' is not supported.`) + NcError.badRequest(`'${sub_op}' is not supported.`); } if ( (op === 'isWithin' && !IS_WITHIN_COMPARISON_SUB_OPS.includes(sub_op)) || (op !== 'isWithin' && IS_WITHIN_COMPARISON_SUB_OPS.includes(sub_op)) ) { - NcError.badRequest(`'${sub_op}' is not supported for '${op}'`) + NcError.badRequest(`'${sub_op}' is not supported for '${op}'`); } } } @@ -3320,30 +3330,30 @@ function validateFilterComparison(uidt: UITypes, op: any, sub_op?: any) { function extractCondition(nestedArrayConditions, aliasColObjMap) { return nestedArrayConditions?.map((str) => { let [logicOp, alias, op, value] = - str.match(/(?:~(and|or|not))?\((.*?),(\w+),(.*)\)/)?.slice(1) || [] + str.match(/(?:~(and|or|not))?\((.*?),(\w+),(.*)\)/)?.slice(1) || []; if (!alias && !op && !value) { // try match with blank filter format [logicOp, alias, op, value] = - str.match(/(?:~(and|or|not))?\((.*?),(\w+)\)/)?.slice(1) || [] + str.match(/(?:~(and|or|not))?\((.*?),(\w+)\)/)?.slice(1) || []; } - let sub_op = null + let sub_op = null; if (aliasColObjMap[alias]) { if ( [UITypes.Date, UITypes.DateTime].includes(aliasColObjMap[alias].uidt) ) { - value = value?.split(',') + value = value?.split(','); // the first element would be sub_op - sub_op = value?.[0] + sub_op = value?.[0]; // remove the first element which is sub_op - value?.shift() - value = value?.[0] + value?.shift(); + value = value?.[0]; } else if (op === 'in') { - value = value.split(',') + value = value.split(','); } - validateFilterComparison(aliasColObjMap[alias].uidt, op, sub_op) + validateFilterComparison(aliasColObjMap[alias].uidt, op, sub_op); } return new Filter({ @@ -3352,8 +3362,8 @@ function extractCondition(nestedArrayConditions, aliasColObjMap) { fk_column_id: aliasColObjMap[alias]?.id, logical_op: logicOp, value, - }) - }) + }); + }); } function applyPaginate( @@ -3364,26 +3374,26 @@ function applyPaginate( ignoreLimit = false, }: XcFilter & { ignoreLimit?: boolean }, ) { - query.offset(offset) - if (!ignoreLimit) query.limit(limit) - return query + query.offset(offset); + if (!ignoreLimit) query.limit(limit); + return query; } function _wherePk(primaryKeys: Column[], id) { - const ids = (id + '').split('___') - const where = {} + const ids = (id + '').split('___'); + const where = {}; for (let i = 0; i < primaryKeys.length; ++i) { - where[primaryKeys[i].column_name] = ids[i] + where[primaryKeys[i].column_name] = ids[i]; } - return where + return where; } function getCompositePk(primaryKeys: Column[], row) { - return primaryKeys.map((c) => row[c.title]).join('___') + return primaryKeys.map((c) => row[c.title]).join('___'); } function haveFormulaColumn(columns: Column[]) { - return columns.some((c) => c.uidt === UITypes.Formula) + return columns.some((c) => c.uidt === UITypes.Formula); } function shouldSkipField( @@ -3394,7 +3404,7 @@ function shouldSkipField( extractPkAndPv, ) { if (fieldsSet) { - return !fieldsSet.has(column.title) + return !fieldsSet.has(column.title); } else { if (!extractPkAndPv) { if (!(viewOrTableColumn instanceof Column)) { @@ -3404,18 +3414,18 @@ function shouldSkipField( !column.pk && column.uidt !== UITypes.ForeignKey ) - return true + return true; if ( !view?.show_system_fields && column.uidt !== UITypes.ForeignKey && !column.pk && isSystemColumn(column) ) - return true + return true; } } - return false + return false; } } -export { BaseModelSqlv2 } +export { BaseModelSqlv2 };