|
|
|
@ -4,6 +4,7 @@ import DataLoader from 'dataloader';
|
|
|
|
|
import dayjs from 'dayjs'; |
|
|
|
|
import utc from 'dayjs/plugin/utc.js'; |
|
|
|
|
import timezone from 'dayjs/plugin/timezone'; |
|
|
|
|
import equal from 'fast-deep-equal'; |
|
|
|
|
import { nocoExecute } from 'nc-help'; |
|
|
|
|
import { |
|
|
|
|
AuditOperationSubTypes, |
|
|
|
@ -260,11 +261,12 @@ class BaseModelSqlv2 {
|
|
|
|
|
} = {}, |
|
|
|
|
validateFormula = false, |
|
|
|
|
): Promise<any> { |
|
|
|
|
const columns = await this.model.getColumns(); |
|
|
|
|
const { where, ...rest } = this._getListArgs(args as any); |
|
|
|
|
const qb = this.dbDriver(this.tnPath); |
|
|
|
|
await this.selectObject({ ...args, qb, validateFormula }); |
|
|
|
|
await this.selectObject({ ...args, qb, validateFormula, columns }); |
|
|
|
|
|
|
|
|
|
const aliasColObjMap = await this.model.getAliasColObjMap(); |
|
|
|
|
const aliasColObjMap = await this.model.getAliasColObjMap(columns); |
|
|
|
|
const sorts = extractSortsObject(rest?.sort, aliasColObjMap); |
|
|
|
|
const filterObj = extractFilterFromXwhere(where, aliasColObjMap); |
|
|
|
|
|
|
|
|
@ -296,8 +298,7 @@ class BaseModelSqlv2 {
|
|
|
|
|
try { |
|
|
|
|
data = await this.execAndParse(qb, null, { first: true }); |
|
|
|
|
} catch (e) { |
|
|
|
|
if (validateFormula || !haveFormulaColumn(await this.model.getColumns())) |
|
|
|
|
throw e; |
|
|
|
|
if (validateFormula || !haveFormulaColumn(columns)) throw e; |
|
|
|
|
logger.log(e); |
|
|
|
|
return this.findOne(args, true); |
|
|
|
|
} |
|
|
|
@ -319,6 +320,7 @@ class BaseModelSqlv2 {
|
|
|
|
|
sort?: string | string[]; |
|
|
|
|
fieldsSet?: Set<string>; |
|
|
|
|
limitOverride?: number; |
|
|
|
|
pks?: string; |
|
|
|
|
} = {}, |
|
|
|
|
options: { |
|
|
|
|
ignoreViewFilterAndSort?: boolean; |
|
|
|
@ -336,6 +338,8 @@ class BaseModelSqlv2 {
|
|
|
|
|
limitOverride, |
|
|
|
|
} = options; |
|
|
|
|
|
|
|
|
|
const columns = await this.model.getColumns(); |
|
|
|
|
|
|
|
|
|
const { where, fields, ...rest } = this._getListArgs(args as any); |
|
|
|
|
|
|
|
|
|
const qb = this.dbDriver(this.tnPath); |
|
|
|
@ -345,12 +349,13 @@ class BaseModelSqlv2 {
|
|
|
|
|
fieldsSet: args.fieldsSet, |
|
|
|
|
viewId: this.viewId, |
|
|
|
|
validateFormula, |
|
|
|
|
columns, |
|
|
|
|
}); |
|
|
|
|
if (+rest?.shuffle) { |
|
|
|
|
await this.shuffle({ qb }); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const aliasColObjMap = await this.model.getAliasColObjMap(); |
|
|
|
|
const aliasColObjMap = await this.model.getAliasColObjMap(columns); |
|
|
|
|
let sorts = extractSortsObject( |
|
|
|
|
rest?.sort, |
|
|
|
|
aliasColObjMap, |
|
|
|
@ -453,8 +458,7 @@ class BaseModelSqlv2 {
|
|
|
|
|
try { |
|
|
|
|
data = await this.execAndParse(qb); |
|
|
|
|
} catch (e) { |
|
|
|
|
if (validateFormula || !haveFormulaColumn(await this.model.getColumns())) |
|
|
|
|
throw e; |
|
|
|
|
if (validateFormula || !haveFormulaColumn(columns)) throw e; |
|
|
|
|
logger.log(e); |
|
|
|
|
return this.list(args, { |
|
|
|
|
ignoreViewFilterAndSort, |
|
|
|
@ -474,13 +478,13 @@ class BaseModelSqlv2 {
|
|
|
|
|
ignoreViewFilterAndSort = false, |
|
|
|
|
throwErrorIfInvalidParams = false, |
|
|
|
|
): Promise<any> { |
|
|
|
|
await this.model.getColumns(); |
|
|
|
|
const columns = await this.model.getColumns(); |
|
|
|
|
const { where } = this._getListArgs(args); |
|
|
|
|
|
|
|
|
|
const qb = this.dbDriver(this.tnPath); |
|
|
|
|
|
|
|
|
|
// qb.xwhere(where, await this.model.getAliasColMapping());
|
|
|
|
|
const aliasColObjMap = await this.model.getAliasColObjMap(); |
|
|
|
|
const aliasColObjMap = await this.model.getAliasColObjMap(columns); |
|
|
|
|
const filterObj = extractFilterFromXwhere( |
|
|
|
|
where, |
|
|
|
|
aliasColObjMap, |
|
|
|
@ -562,6 +566,8 @@ class BaseModelSqlv2 {
|
|
|
|
|
widgetFilterArr?: Filter[]; |
|
|
|
|
}, |
|
|
|
|
) { |
|
|
|
|
const columns = await this.model.getColumns(); |
|
|
|
|
|
|
|
|
|
const { where, ...rest } = this._getListArgs(args as any); |
|
|
|
|
|
|
|
|
|
const qb = this.dbDriver(this.tnPath); |
|
|
|
@ -579,7 +585,7 @@ class BaseModelSqlv2 {
|
|
|
|
|
await this.shuffle({ qb }); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const aliasColObjMap = await this.model.getAliasColObjMap(); |
|
|
|
|
const aliasColObjMap = await this.model.getAliasColObjMap(columns); |
|
|
|
|
|
|
|
|
|
const filterObj = extractFilterFromXwhere(where, aliasColObjMap); |
|
|
|
|
await conditionV2( |
|
|
|
@ -621,7 +627,7 @@ class BaseModelSqlv2 {
|
|
|
|
|
|
|
|
|
|
args.column_name = args.column_name || ''; |
|
|
|
|
|
|
|
|
|
const cols = await this.model.getColumns(); |
|
|
|
|
const columns = await this.model.getColumns(); |
|
|
|
|
const groupByColumns: Record<string, Column> = {}; |
|
|
|
|
|
|
|
|
|
const selectors = []; |
|
|
|
@ -630,7 +636,9 @@ class BaseModelSqlv2 {
|
|
|
|
|
|
|
|
|
|
await Promise.all( |
|
|
|
|
args.column_name.split(',').map(async (col) => { |
|
|
|
|
let column = cols.find((c) => c.column_name === col || c.title === col); |
|
|
|
|
let column = columns.find( |
|
|
|
|
(c) => c.column_name === col || c.title === col, |
|
|
|
|
); |
|
|
|
|
if (!column) { |
|
|
|
|
throw NcError.fieldNotFound(col); |
|
|
|
|
} |
|
|
|
@ -712,7 +720,7 @@ class BaseModelSqlv2 {
|
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
{ |
|
|
|
|
const columnName = await getColumnName(column, cols); |
|
|
|
|
const columnName = await getColumnName(column, columns); |
|
|
|
|
selectors.push( |
|
|
|
|
this.dbDriver.raw('?? as ??', [columnName, column.id]), |
|
|
|
|
); |
|
|
|
@ -735,7 +743,7 @@ class BaseModelSqlv2 {
|
|
|
|
|
await this.shuffle({ qb }); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const aliasColObjMap = await this.model.getAliasColObjMap(); |
|
|
|
|
const aliasColObjMap = await this.model.getAliasColObjMap(columns); |
|
|
|
|
|
|
|
|
|
let sorts = extractSortsObject(rest?.sort, aliasColObjMap); |
|
|
|
|
|
|
|
|
@ -788,10 +796,7 @@ class BaseModelSqlv2 {
|
|
|
|
|
column.uidt as UITypes, |
|
|
|
|
) |
|
|
|
|
) { |
|
|
|
|
const columnName = await getColumnName( |
|
|
|
|
column, |
|
|
|
|
await this.model.getColumns(), |
|
|
|
|
); |
|
|
|
|
const columnName = await getColumnName(column, columns); |
|
|
|
|
|
|
|
|
|
const baseUsers = await BaseUser.getUsersList({ |
|
|
|
|
base_id: column.base_id, |
|
|
|
@ -843,11 +848,12 @@ class BaseModelSqlv2 {
|
|
|
|
|
const groupBySelectors = []; |
|
|
|
|
const getAlias = getAliasGenerator('__nc_gb'); |
|
|
|
|
|
|
|
|
|
const columns = await this.model.getColumns(); |
|
|
|
|
|
|
|
|
|
// todo: refactor and avoid duplicate code
|
|
|
|
|
await this.model.getColumns().then((cols) => |
|
|
|
|
Promise.all( |
|
|
|
|
await Promise.all( |
|
|
|
|
args.column_name.split(',').map(async (col) => { |
|
|
|
|
let column = cols.find( |
|
|
|
|
let column = columns.find( |
|
|
|
|
(c) => c.column_name === col || c.title === col, |
|
|
|
|
); |
|
|
|
|
if (!column) { |
|
|
|
@ -880,8 +886,7 @@ class BaseModelSqlv2 {
|
|
|
|
|
knex: this.dbDriver, |
|
|
|
|
// column,
|
|
|
|
|
// alias,
|
|
|
|
|
columnOptions: |
|
|
|
|
(await column.getColOptions()) as RollupColumn, |
|
|
|
|
columnOptions: (await column.getColOptions()) as RollupColumn, |
|
|
|
|
}) |
|
|
|
|
).builder.as(sanitize(column.id)), |
|
|
|
|
); |
|
|
|
@ -932,7 +937,7 @@ class BaseModelSqlv2 {
|
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
{ |
|
|
|
|
const columnName = await getColumnName(column, cols); |
|
|
|
|
const columnName = await getColumnName(column, columns); |
|
|
|
|
selectors.push( |
|
|
|
|
this.dbDriver.raw('?? as ??', [columnName, column.id]), |
|
|
|
|
); |
|
|
|
@ -941,14 +946,13 @@ class BaseModelSqlv2 {
|
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
}), |
|
|
|
|
), |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
const qb = this.dbDriver(this.tnPath); |
|
|
|
|
qb.count(`${this.model.primaryKey?.column_name || '*'} as count`); |
|
|
|
|
qb.select(...selectors); |
|
|
|
|
|
|
|
|
|
const aliasColObjMap = await this.model.getAliasColObjMap(); |
|
|
|
|
const aliasColObjMap = await this.model.getAliasColObjMap(columns); |
|
|
|
|
|
|
|
|
|
const filterObj = extractFilterFromXwhere(where, aliasColObjMap); |
|
|
|
|
await conditionV2( |
|
|
|
@ -2452,7 +2456,7 @@ class BaseModelSqlv2 {
|
|
|
|
|
// const columns = _columns ?? (await this.model.getColumns());
|
|
|
|
|
// for (const column of columns) {
|
|
|
|
|
viewOrTableColumns = |
|
|
|
|
_columns || viewColumns || (await this.model.getColumns()); |
|
|
|
|
viewColumns || _columns || (await this.model.getColumns()); |
|
|
|
|
} |
|
|
|
|
for (const viewOrTableColumn of viewOrTableColumns) { |
|
|
|
|
const column = |
|
|
|
@ -2484,7 +2488,7 @@ class BaseModelSqlv2 {
|
|
|
|
|
{ |
|
|
|
|
const columnName = await getColumnName( |
|
|
|
|
column, |
|
|
|
|
await this.model.getColumns(), |
|
|
|
|
_columns || (await this.model.getColumns()), |
|
|
|
|
); |
|
|
|
|
if (this.isMySQL) { |
|
|
|
|
// MySQL stores timestamp in UTC but display in timezone
|
|
|
|
@ -2651,7 +2655,7 @@ class BaseModelSqlv2 {
|
|
|
|
|
case UITypes.LastModifiedBy: { |
|
|
|
|
const columnName = await getColumnName( |
|
|
|
|
column, |
|
|
|
|
await this.model.getColumns(), |
|
|
|
|
_columns || (await this.model.getColumns()), |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
res[sanitize(column.id || columnName)] = sanitize( |
|
|
|
@ -2705,9 +2709,10 @@ class BaseModelSqlv2 {
|
|
|
|
|
data, |
|
|
|
|
this.clientMeta, |
|
|
|
|
this.dbDriver, |
|
|
|
|
columns, |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
await this.validate(insertObj); |
|
|
|
|
await this.validate(insertObj, columns); |
|
|
|
|
|
|
|
|
|
if ('beforeInsert' in this) { |
|
|
|
|
await this.beforeInsert(insertObj, trx, cookie); |
|
|
|
@ -2952,13 +2957,16 @@ class BaseModelSqlv2 {
|
|
|
|
|
|
|
|
|
|
async updateByPk(id, data, trx?, cookie?, _disableOptimization = false) { |
|
|
|
|
try { |
|
|
|
|
const columns = await this.model.getColumns(); |
|
|
|
|
|
|
|
|
|
const updateObj = await this.model.mapAliasToColumn( |
|
|
|
|
data, |
|
|
|
|
this.clientMeta, |
|
|
|
|
this.dbDriver, |
|
|
|
|
columns, |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
await this.validate(data); |
|
|
|
|
await this.validate(data, columns); |
|
|
|
|
|
|
|
|
|
await this.beforeUpdate(data, trx, cookie); |
|
|
|
|
|
|
|
|
@ -2973,7 +2981,7 @@ class BaseModelSqlv2 {
|
|
|
|
|
|
|
|
|
|
const query = this.dbDriver(this.tnPath) |
|
|
|
|
.update(updateObj) |
|
|
|
|
.where(await this._wherePk(id)); |
|
|
|
|
.where(await this._wherePk(id, true)); |
|
|
|
|
|
|
|
|
|
await this.execAndParse(query, null, { raw: true }); |
|
|
|
|
|
|
|
|
@ -2995,11 +3003,15 @@ class BaseModelSqlv2 {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
async _wherePk(id) { |
|
|
|
|
await this.model.getColumns(); |
|
|
|
|
async _wherePk(id, skipGetColumns = false) { |
|
|
|
|
if (!skipGetColumns) await this.model.getColumns(); |
|
|
|
|
return _wherePk(this.model.primaryKeys, id); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
comparePks(pk1, pk2) { |
|
|
|
|
return equal(pk1, pk2); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public getTnPath(tb: { table_name: string } | string, alias?: string) { |
|
|
|
|
const tn = typeof tb === 'string' ? tb : tb.table_name; |
|
|
|
|
const schema = (this.dbDriver as any).searchPath?.(); |
|
|
|
@ -3088,23 +3100,25 @@ class BaseModelSqlv2 {
|
|
|
|
|
try { |
|
|
|
|
const source = await Source.get(this.model.source_id); |
|
|
|
|
await populatePk(this.model, data); |
|
|
|
|
|
|
|
|
|
const columns = await this.model.getColumns(); |
|
|
|
|
|
|
|
|
|
const insertObj = await this.model.mapAliasToColumn( |
|
|
|
|
data, |
|
|
|
|
this.clientMeta, |
|
|
|
|
this.dbDriver, |
|
|
|
|
columns, |
|
|
|
|
); |
|
|
|
|
let rowId = null; |
|
|
|
|
|
|
|
|
|
const nestedCols = (await this.model.getColumns()).filter((c) => |
|
|
|
|
isLinksOrLTAR(c), |
|
|
|
|
); |
|
|
|
|
const nestedCols = columns.filter((c) => isLinksOrLTAR(c)); |
|
|
|
|
const { postInsertOps, preInsertOps } = await this.prepareNestedLinkQb({ |
|
|
|
|
nestedCols, |
|
|
|
|
data, |
|
|
|
|
insertObj, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
await this.validate(insertObj); |
|
|
|
|
await this.validate(insertObj, columns); |
|
|
|
|
|
|
|
|
|
await this.beforeInsert(insertObj, this.dbDriver, cookie); |
|
|
|
|
|
|
|
|
@ -3402,11 +3416,9 @@ class BaseModelSqlv2 {
|
|
|
|
|
let agPkCol: Column; |
|
|
|
|
|
|
|
|
|
if (!raw) { |
|
|
|
|
const nestedCols = (await this.model.getColumns()).filter((c) => |
|
|
|
|
isLinksOrLTAR(c), |
|
|
|
|
); |
|
|
|
|
const columns = await this.model.getColumns(); |
|
|
|
|
|
|
|
|
|
await this.model.getColumns(); |
|
|
|
|
const nestedCols = columns.filter((c) => isLinksOrLTAR(c)); |
|
|
|
|
|
|
|
|
|
for (const d of datas) { |
|
|
|
|
const insertObj = {}; |
|
|
|
@ -3687,12 +3699,12 @@ class BaseModelSqlv2 {
|
|
|
|
|
) { |
|
|
|
|
let transaction; |
|
|
|
|
try { |
|
|
|
|
if (raw) await this.model.getColumns(); |
|
|
|
|
const columns = await this.model.getColumns(); |
|
|
|
|
|
|
|
|
|
// validate update data
|
|
|
|
|
if (!raw) { |
|
|
|
|
for (const d of datas) { |
|
|
|
|
await this.validate(d); |
|
|
|
|
await this.validate(d, columns); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -3700,7 +3712,12 @@ class BaseModelSqlv2 {
|
|
|
|
|
? datas |
|
|
|
|
: await Promise.all( |
|
|
|
|
datas.map((d) => |
|
|
|
|
this.model.mapAliasToColumn(d, this.clientMeta, this.dbDriver), |
|
|
|
|
this.model.mapAliasToColumn( |
|
|
|
|
d, |
|
|
|
|
this.clientMeta, |
|
|
|
|
this.dbDriver, |
|
|
|
|
columns, |
|
|
|
|
), |
|
|
|
|
), |
|
|
|
|
); |
|
|
|
|
|
|
|
|
@ -3708,8 +3725,10 @@ class BaseModelSqlv2 {
|
|
|
|
|
const newData = []; |
|
|
|
|
const updatePkValues = []; |
|
|
|
|
const toBeUpdated = []; |
|
|
|
|
for (const d of updateDatas) { |
|
|
|
|
const pkValues = await this._extractPksValues(d); |
|
|
|
|
const pkAndData: { pk: any; data: any }[] = []; |
|
|
|
|
const readChunkSize = 100; |
|
|
|
|
for (const [i, d] of updateDatas.entries()) { |
|
|
|
|
const pkValues = this._extractPksValues(d); |
|
|
|
|
if (!pkValues) { |
|
|
|
|
// throw or skip if no pk provided
|
|
|
|
|
if (throwExceptionIfNotExist) { |
|
|
|
@ -3720,20 +3739,59 @@ class BaseModelSqlv2 {
|
|
|
|
|
if (!raw) { |
|
|
|
|
await this.prepareNocoData(d, false, cookie); |
|
|
|
|
|
|
|
|
|
const oldRecord = await this.readByPk(pkValues); |
|
|
|
|
pkAndData.push({ |
|
|
|
|
pk: pkValues, |
|
|
|
|
data: d, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
if ( |
|
|
|
|
pkAndData.length >= readChunkSize || |
|
|
|
|
i === updateDatas.length - 1 |
|
|
|
|
) { |
|
|
|
|
const tempToRead = pkAndData.splice(0, pkAndData.length); |
|
|
|
|
const oldRecords = await this.list( |
|
|
|
|
{ |
|
|
|
|
pks: tempToRead.map((v) => v.pk).join(','), |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
limitOverride: tempToRead.length, |
|
|
|
|
}, |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
if (oldRecords.length === tempToRead.length) { |
|
|
|
|
prevData.push(...oldRecords); |
|
|
|
|
} else { |
|
|
|
|
for (const recordPk of tempToRead) { |
|
|
|
|
const oldRecord = oldRecords.find((r) => |
|
|
|
|
this.comparePks(this._extractPksValues(r), recordPk), |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
if (!oldRecord) { |
|
|
|
|
// throw or skip if no record found
|
|
|
|
|
if (throwExceptionIfNotExist) { |
|
|
|
|
NcError.recordNotFound(JSON.stringify(pkValues)); |
|
|
|
|
NcError.recordNotFound(JSON.stringify(recordPk)); |
|
|
|
|
} |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
prevData.push(oldRecord); |
|
|
|
|
} |
|
|
|
|
const wherePk = await this._wherePk(pkValues); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (const { pk, data } of tempToRead) { |
|
|
|
|
const wherePk = await this._wherePk(pk, true); |
|
|
|
|
toBeUpdated.push({ d: data, wherePk }); |
|
|
|
|
updatePkValues.push(pk); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
const wherePk = await this._wherePk(pkValues, true); |
|
|
|
|
|
|
|
|
|
toBeUpdated.push({ d, wherePk }); |
|
|
|
|
|
|
|
|
|
updatePkValues.push(pkValues); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
transaction = await this.dbDriver.transaction(); |
|
|
|
|
|
|
|
|
@ -3744,9 +3802,17 @@ class BaseModelSqlv2 {
|
|
|
|
|
await transaction.commit(); |
|
|
|
|
|
|
|
|
|
if (!raw) { |
|
|
|
|
for (const pkValues of updatePkValues) { |
|
|
|
|
const updatedRecord = await this.readByPk(pkValues); |
|
|
|
|
newData.push(updatedRecord); |
|
|
|
|
while (updatePkValues.length) { |
|
|
|
|
const updatedRecords = await this.list( |
|
|
|
|
{ |
|
|
|
|
pks: updatePkValues.splice(0, readChunkSize).join(','), |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
limitOverride: readChunkSize, |
|
|
|
|
}, |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
newData.push(...updatedRecords); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -3783,23 +3849,27 @@ class BaseModelSqlv2 {
|
|
|
|
|
) { |
|
|
|
|
try { |
|
|
|
|
let count = 0; |
|
|
|
|
|
|
|
|
|
const columns = await this.model.getColumns(); |
|
|
|
|
|
|
|
|
|
const updateData = await this.model.mapAliasToColumn( |
|
|
|
|
data, |
|
|
|
|
this.clientMeta, |
|
|
|
|
this.dbDriver, |
|
|
|
|
columns, |
|
|
|
|
); |
|
|
|
|
if (!args.skipValidationAndHooks) await this.validate(updateData); |
|
|
|
|
if (!args.skipValidationAndHooks) |
|
|
|
|
await this.validate(updateData, columns); |
|
|
|
|
|
|
|
|
|
await this.prepareNocoData(updateData, false, cookie); |
|
|
|
|
|
|
|
|
|
const pkValues = await this._extractPksValues(updateData); |
|
|
|
|
const pkValues = 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 aliasColObjMap = await this.model.getAliasColObjMap(columns); |
|
|
|
|
const filterObj = extractFilterFromXwhere(where, aliasColObjMap, true); |
|
|
|
|
|
|
|
|
|
const conditionObj = [ |
|
|
|
@ -3864,18 +3934,27 @@ class BaseModelSqlv2 {
|
|
|
|
|
isSingleRecordDeletion?: boolean; |
|
|
|
|
} = {}, |
|
|
|
|
) { |
|
|
|
|
const columns = await this.model.getColumns(); |
|
|
|
|
|
|
|
|
|
let transaction; |
|
|
|
|
try { |
|
|
|
|
const deleteIds = await Promise.all( |
|
|
|
|
ids.map((d) => |
|
|
|
|
this.model.mapAliasToColumn(d, this.clientMeta, this.dbDriver), |
|
|
|
|
this.model.mapAliasToColumn( |
|
|
|
|
d, |
|
|
|
|
this.clientMeta, |
|
|
|
|
this.dbDriver, |
|
|
|
|
columns, |
|
|
|
|
), |
|
|
|
|
), |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
const deleted = []; |
|
|
|
|
const res = []; |
|
|
|
|
for (const d of deleteIds) { |
|
|
|
|
const pkValues = await this._extractPksValues(d); |
|
|
|
|
const pkAndData: { pk: any; data: any }[] = []; |
|
|
|
|
const readChunkSize = 100; |
|
|
|
|
for (const [i, d] of deleteIds.entries()) { |
|
|
|
|
const pkValues = this._extractPksValues(d); |
|
|
|
|
if (!pkValues) { |
|
|
|
|
// throw or skip if no pk provided
|
|
|
|
|
if (throwExceptionIfNotExist) { |
|
|
|
@ -3884,17 +3963,41 @@ class BaseModelSqlv2 {
|
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const deletedRecord = await this.readByPk(pkValues); |
|
|
|
|
if (!deletedRecord) { |
|
|
|
|
pkAndData.push({ pk: pkValues, data: d }); |
|
|
|
|
|
|
|
|
|
if (pkAndData.length >= readChunkSize || i === deleteIds.length - 1) { |
|
|
|
|
const tempToRead = pkAndData.splice(0, pkAndData.length); |
|
|
|
|
const oldRecords = await this.list( |
|
|
|
|
{ |
|
|
|
|
pks: tempToRead.map((v) => v.pk).join(','), |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
limitOverride: tempToRead.length, |
|
|
|
|
}, |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
if (oldRecords.length === tempToRead.length) { |
|
|
|
|
deleted.push(...oldRecords); |
|
|
|
|
res.push(...tempToRead.map((v) => v.data)); |
|
|
|
|
} else { |
|
|
|
|
for (const { pk, data } of tempToRead) { |
|
|
|
|
const oldRecord = oldRecords.find((r) => |
|
|
|
|
this.comparePks(this._extractPksValues(r), pk), |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
if (!oldRecord) { |
|
|
|
|
// throw or skip if no record found
|
|
|
|
|
if (throwExceptionIfNotExist) { |
|
|
|
|
NcError.recordNotFound(JSON.stringify(pkValues)); |
|
|
|
|
NcError.recordNotFound(JSON.stringify(pk)); |
|
|
|
|
} |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
deleted.push(deletedRecord); |
|
|
|
|
|
|
|
|
|
res.push(d); |
|
|
|
|
deleted.push(oldRecord); |
|
|
|
|
res.push(data); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const execQueries: (( |
|
|
|
@ -3989,10 +4092,10 @@ class BaseModelSqlv2 {
|
|
|
|
|
) { |
|
|
|
|
let trx: Knex.Transaction; |
|
|
|
|
try { |
|
|
|
|
await this.model.getColumns(); |
|
|
|
|
const columns = await this.model.getColumns(); |
|
|
|
|
const { where } = this._getListArgs(args); |
|
|
|
|
const qb = this.dbDriver(this.tnPath); |
|
|
|
|
const aliasColObjMap = await this.model.getAliasColObjMap(); |
|
|
|
|
const aliasColObjMap = await this.model.getAliasColObjMap(columns); |
|
|
|
|
const filterObj = extractFilterFromXwhere(where, aliasColObjMap, true); |
|
|
|
|
|
|
|
|
|
await conditionV2( |
|
|
|
@ -4336,10 +4439,13 @@ class BaseModelSqlv2 {
|
|
|
|
|
|
|
|
|
|
protected async errorDelete(_e, _id, _trx, _cookie) {} |
|
|
|
|
|
|
|
|
|
async validate(data: Record<string, any>): Promise<boolean> { |
|
|
|
|
await this.model.getColumns(); |
|
|
|
|
async validate( |
|
|
|
|
data: Record<string, any>, |
|
|
|
|
columns?: Column[], |
|
|
|
|
): Promise<boolean> { |
|
|
|
|
const cols = columns || (await this.model.getColumns()); |
|
|
|
|
// let cols = Object.keys(this.columns);
|
|
|
|
|
for (let i = 0; i < this.model.columns.length; ++i) { |
|
|
|
|
for (let i = 0; i < cols.length; ++i) { |
|
|
|
|
const column = this.model.columns[i]; |
|
|
|
|
|
|
|
|
|
if ( |
|
|
|
@ -4836,9 +4942,8 @@ class BaseModelSqlv2 {
|
|
|
|
|
> { |
|
|
|
|
try { |
|
|
|
|
const { where, ...rest } = this._getListArgs(args as any); |
|
|
|
|
const column = await this.model |
|
|
|
|
.getColumns() |
|
|
|
|
.then((cols) => cols?.find((col) => col.id === args.groupColumnId)); |
|
|
|
|
const columns = await this.model.getColumns(); |
|
|
|
|
const column = columns?.find((col) => col.id === args.groupColumnId); |
|
|
|
|
|
|
|
|
|
if (!column) NcError.fieldNotFound(args.groupColumnId); |
|
|
|
|
if (isVirtualCol(column)) |
|
|
|
@ -4876,7 +4981,7 @@ class BaseModelSqlv2 {
|
|
|
|
|
await this.selectObject({ qb, extractPkAndPv: true }); |
|
|
|
|
|
|
|
|
|
// todo: refactor and move to a method (applyFilterAndSort)
|
|
|
|
|
const aliasColObjMap = await this.model.getAliasColObjMap(); |
|
|
|
|
const aliasColObjMap = await this.model.getAliasColObjMap(columns); |
|
|
|
|
let sorts = extractSortsObject(args?.sort, aliasColObjMap); |
|
|
|
|
const filterObj = extractFilterFromXwhere(where, aliasColObjMap); |
|
|
|
|
// todo: replace with view id
|
|
|
|
@ -4998,9 +5103,8 @@ class BaseModelSqlv2 {
|
|
|
|
|
ignoreViewFilterAndSort?: boolean; |
|
|
|
|
} & XcFilter, |
|
|
|
|
) { |
|
|
|
|
const column = await this.model |
|
|
|
|
.getColumns() |
|
|
|
|
.then((cols) => cols?.find((col) => col.id === args.groupColumnId)); |
|
|
|
|
const columns = await this.model.getColumns(); |
|
|
|
|
const column = columns?.find((col) => col.id === args.groupColumnId); |
|
|
|
|
|
|
|
|
|
if (!column) NcError.fieldNotFound(args.groupColumnId); |
|
|
|
|
if (isVirtualCol(column)) |
|
|
|
@ -5011,7 +5115,7 @@ class BaseModelSqlv2 {
|
|
|
|
|
.groupBy(column.column_name); |
|
|
|
|
|
|
|
|
|
// todo: refactor and move to a common method (applyFilterAndSort)
|
|
|
|
|
const aliasColObjMap = await this.model.getAliasColObjMap(); |
|
|
|
|
const aliasColObjMap = await this.model.getAliasColObjMap(columns); |
|
|
|
|
const filterObj = extractFilterFromXwhere(args.where, aliasColObjMap); |
|
|
|
|
// todo: replace with view id
|
|
|
|
|
|
|
|
|
@ -6192,12 +6296,12 @@ class BaseModelSqlv2 {
|
|
|
|
|
args: { limit?; offset?; fieldSet?: Set<string> } = {}, |
|
|
|
|
) { |
|
|
|
|
try { |
|
|
|
|
const columns = await this.model.getColumns(); |
|
|
|
|
|
|
|
|
|
const { where, sort } = this._getListArgs(args as any); |
|
|
|
|
// todo: get only required fields
|
|
|
|
|
|
|
|
|
|
const relColumn = (await this.model.getColumns()).find( |
|
|
|
|
(c) => c.id === colId, |
|
|
|
|
); |
|
|
|
|
const relColumn = columns.find((c) => c.id === colId); |
|
|
|
|
|
|
|
|
|
const row = await this.execAndParse( |
|
|
|
|
this.dbDriver(this.tnPath).where(await this._wherePk(id)), |
|
|
|
|