Browse Source

refactor: move formula helpers to sdk

pull/1979/head
Wing-Kam Wong 3 years ago
parent
commit
9d5bce4a6a
  1. 88
      packages/nocodb-sdk/src/lib/formulaHelpers.ts
  2. 10
      packages/nocodb/src/lib/dataMapper/lib/sql/formulav2/formulaQueryBuilderv2.ts
  3. 9
      packages/nocodb/src/lib/noco/meta/api/columnApis.ts
  4. 60
      packages/nocodb/src/lib/noco/meta/helpers/formulaHelpers.ts
  5. 8
      packages/nocodb/src/lib/noco/upgrader/jobs/ncProjectUpgraderV2_0090000.ts

88
packages/nocodb-sdk/src/lib/formulaHelpers.ts

@ -2,6 +2,65 @@ import jsep from 'jsep';
import { ColumnType } from './Api'; import { ColumnType } from './Api';
export const jsepCurlyHook = {
name: 'curly',
init(jsep) {
jsep.hooks.add('gobble-token', function gobbleCurlyLiteral(env) {
const OCURLY_CODE = 123; // {
const CCURLY_CODE = 125; // }
const { context } = env;
if (
!jsep.isIdentifierStart(context.code) &&
context.code === OCURLY_CODE
) {
context.index += 1;
const nodes = context.gobbleExpressions(CCURLY_CODE);
if (context.code === CCURLY_CODE) {
context.index += 1;
if (nodes.length > 0) {
env.node = nodes[0];
}
return env.node;
} else {
context.throwError('Unclosed }');
}
}
});
},
} as jsep.IPlugin;
export async function substituteColumnAliasWithIdInFormula(
formula,
columns: ColumnType[]
) {
const substituteId = async (pt: any) => {
if (pt.type === 'CallExpression') {
for (const arg of pt.arguments || []) {
await substituteId(arg);
}
} else if (pt.type === 'Literal') {
return;
} else if (pt.type === 'Identifier') {
const colNameOrId = pt.name;
const column = columns.find(
(c) =>
c.id === colNameOrId ||
c.column_name === colNameOrId ||
c.title === colNameOrId
);
pt.name = '{' + column.id + '}';
} else if (pt.type === 'BinaryExpression') {
await substituteId(pt.left);
await substituteId(pt.right);
}
};
// register jsep curly hook
jsep.plugins.register(jsepCurlyHook);
const parsedFormula = jsep(formula);
await substituteId(parsedFormula);
return jsepTreeToFormula(parsedFormula);
}
export function substituteColumnIdWithAliasInFormula( export function substituteColumnIdWithAliasInFormula(
formula, formula,
columns: ColumnType[], columns: ColumnType[],
@ -30,33 +89,8 @@ export function substituteColumnIdWithAliasInFormula(
} }
}; };
// register curly hook // register jsep curly hook
jsep.plugins.register({ jsep.plugins.register(jsepCurlyHook);
name: 'curly',
init(jsep) {
jsep.hooks.add('gobble-token', function gobbleCurlyLiteral(env) {
const OCURLY_CODE = 123; // {
const CCURLY_CODE = 125; // }
const { context } = env;
if (
!jsep.isIdentifierStart(context.code) &&
context.code === OCURLY_CODE
) {
context.index += 1;
const nodes = context.gobbleExpressions(CCURLY_CODE);
if (context.code === CCURLY_CODE) {
context.index += 1;
if (nodes.length > 0) {
env.node = nodes[0];
}
return env.node;
} else {
context.throwError('Unclosed }');
}
}
});
},
} as jsep.IPlugin);
const parsedFormula = jsep(formula); const parsedFormula = jsep(formula);
const parsedRawFormula = rawFormula && jsep(rawFormula); const parsedRawFormula = rawFormula && jsep(rawFormula);
substituteId(parsedFormula, parsedRawFormula); substituteId(parsedFormula, parsedRawFormula);

10
packages/nocodb/src/lib/dataMapper/lib/sql/formulav2/formulaQueryBuilderv2.ts

@ -7,7 +7,7 @@ import FormulaColumn from '../../../../noco-models/FormulaColumn';
import { XKnex } from '../../..'; import { XKnex } from '../../..';
import LinkToAnotherRecordColumn from '../../../../noco-models/LinkToAnotherRecordColumn'; import LinkToAnotherRecordColumn from '../../../../noco-models/LinkToAnotherRecordColumn';
import LookupColumn from '../../../../noco-models/LookupColumn'; import LookupColumn from '../../../../noco-models/LookupColumn';
import { UITypes } from 'nocodb-sdk'; import { jsepCurlyHook, UITypes } from 'nocodb-sdk';
// todo: switch function based on database // todo: switch function based on database
@ -51,6 +51,8 @@ export default async function formulaQueryBuilderv2(
model: Model, model: Model,
aliasToColumn = {} aliasToColumn = {}
) { ) {
// register jsep curly hook
jsep.plugins.register(jsepCurlyHook);
const tree = jsep(_tree); const tree = jsep(_tree);
// todo: improve - implement a common solution for filter, sort, formula, etc // todo: improve - implement a common solution for filter, sort, formula, etc
@ -647,7 +649,11 @@ export default async function formulaQueryBuilderv2(
return query; return query;
} else if (pt.type === 'UnaryExpression') { } else if (pt.type === 'UnaryExpression') {
const query = knex.raw( const query = knex.raw(
`${pt.operator}${fn(pt.argument, null, pt.operator).toQuery()}${colAlias}` `${pt.operator}${fn(
pt.argument,
null,
pt.operator
).toQuery()}${colAlias}`
); );
if (prevBinaryOp && pt.operator !== prevBinaryOp) { if (prevBinaryOp && pt.operator !== prevBinaryOp) {
query.wrap('(', ')'); query.wrap('(', ')');

9
packages/nocodb/src/lib/noco/meta/api/columnApis.ts

@ -3,7 +3,6 @@ import Model from '../../../noco-models/Model';
import ProjectMgrv2 from '../../../sqlMgr/v2/ProjectMgrv2'; import ProjectMgrv2 from '../../../sqlMgr/v2/ProjectMgrv2';
import Base from '../../../noco-models/Base'; import Base from '../../../noco-models/Base';
import Column from '../../../noco-models/Column'; import Column from '../../../noco-models/Column';
import { substituteColumnAliasWithIdInFormula } from '../helpers/formulaHelpers';
import validateParams from '../helpers/validateParams'; import validateParams from '../helpers/validateParams';
import { Tele } from 'nc-help'; import { Tele } from 'nc-help';
@ -19,6 +18,7 @@ import {
isVirtualCol, isVirtualCol,
LinkToAnotherRecordType, LinkToAnotherRecordType,
RelationTypes, RelationTypes,
substituteColumnAliasWithIdInFormula,
substituteColumnIdWithAliasInFormula, substituteColumnIdWithAliasInFormula,
TableType, TableType,
UITypes UITypes
@ -496,9 +496,12 @@ export async function columnAdd(req: Request, res: Response<TableType>) {
}> = (await sqlClient.columnList({ tn: table.table_name }))?.data?.list; }> = (await sqlClient.columnList({ tn: table.table_name }))?.data?.list;
const insertedColumnMeta = const insertedColumnMeta =
columns.find(c => c.cn === colBody.column_name) || {} as any; columns.find(c => c.cn === colBody.column_name) || ({} as any);
if (colBody.uidt === UITypes.SingleSelect || colBody.uidt === UITypes.MultiSelect) { if (
colBody.uidt === UITypes.SingleSelect ||
colBody.uidt === UITypes.MultiSelect
) {
insertedColumnMeta.dtxp = colBody.dtxp; insertedColumnMeta.dtxp = colBody.dtxp;
} }

60
packages/nocodb/src/lib/noco/meta/helpers/formulaHelpers.ts

@ -1,60 +0,0 @@
import jsep from 'jsep';
import jsepTreeToFormula from '../../common/helpers/jsepTreeToFormula';
import Column from '../../../noco-models/Column';
export async function substituteColumnAliasWithIdInFormula(
formula,
columns: Column[]
) {
const substituteId = async (pt: any) => {
if (pt.type === 'CallExpression') {
for (const arg of pt.arguments || []) {
await substituteId(arg);
}
} else if (pt.type === 'Literal') {
return;
} else if (pt.type === 'Identifier') {
const colNameOrId = pt.name;
const column = columns.find(
c =>
c.id === colNameOrId ||
c.column_name === colNameOrId ||
c.title === colNameOrId
);
pt.name = '{' + column.id + '}';
} else if (pt.type === 'BinaryExpression') {
await substituteId(pt.left);
await substituteId(pt.right);
}
};
// register curly hook
jsep.plugins.register({
name: 'curly',
init(jsep) {
jsep.hooks.add('gobble-token', function gobbleCurlyLiteral(env) {
const OCURLY_CODE = 123; // {
const CCURLY_CODE = 125; // }
const { context } = env;
if (
!jsep.isIdentifierStart(context.code) &&
context.code === OCURLY_CODE
) {
context.index += 1;
const nodes = context.gobbleExpressions(CCURLY_CODE);
if (context.code === CCURLY_CODE) {
context.index += 1;
if (nodes.length > 0) {
env.node = nodes[0];
}
return env.node;
} else {
context.throwError('Unclosed }');
}
}
});
}
} as jsep.IPlugin);
const parsedFormula = jsep(formula);
await substituteId(parsedFormula);
return jsepTreeToFormula(parsedFormula);
}

8
packages/nocodb/src/lib/noco/upgrader/jobs/ncProjectUpgraderV2_0090000.ts

@ -4,11 +4,15 @@ import User from '../../../noco-models/User';
import Project from '../../../noco-models/Project'; import Project from '../../../noco-models/Project';
import ProjectUser from '../../../noco-models/ProjectUser'; import ProjectUser from '../../../noco-models/ProjectUser';
import Model from '../../../noco-models/Model'; import Model from '../../../noco-models/Model';
import { ModelTypes, UITypes, ViewTypes } from 'nocodb-sdk'; import {
ModelTypes,
substituteColumnAliasWithIdInFormula,
UITypes,
ViewTypes
} from 'nocodb-sdk';
import Column from '../../../noco-models/Column'; import Column from '../../../noco-models/Column';
import LinkToAnotherRecordColumn from '../../../noco-models/LinkToAnotherRecordColumn'; import LinkToAnotherRecordColumn from '../../../noco-models/LinkToAnotherRecordColumn';
import NcHelp from '../../../utils/NcHelp'; import NcHelp from '../../../utils/NcHelp';
import { substituteColumnAliasWithIdInFormula } from '../../meta/helpers/formulaHelpers';
import RollupColumn from '../../../noco-models/RollupColumn'; import RollupColumn from '../../../noco-models/RollupColumn';
import View from '../../../noco-models/View'; import View from '../../../noco-models/View';
import GridView from '../../../noco-models/GridView'; import GridView from '../../../noco-models/GridView';

Loading…
Cancel
Save