Browse Source

fix(gui): cast division output to float in formula

re #530

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/559/head
Pranav C 3 years ago
parent
commit
a98c9321fa
  1. 37
      packages/nocodb/src/lib/dataMapper/lib/sql/formulaQueryBuilderFromString.ts
  2. 15
      packages/nocodb/src/lib/dataMapper/lib/sql/functionMappings/commonFns.ts
  3. 4
      packages/nocodb/src/lib/dataMapper/lib/sql/functionMappings/mssql.ts
  4. 3
      packages/nocodb/src/lib/dataMapper/lib/sql/functionMappings/mysql.ts
  5. 3
      packages/nocodb/src/lib/dataMapper/lib/sql/functionMappings/pg.ts
  6. 3
      packages/nocodb/src/lib/dataMapper/lib/sql/functionMappings/sqlite.ts
  7. 8
      packages/nocodb/src/lib/dataMapper/lib/sql/mapFunctionName.ts

37
packages/nocodb/src/lib/dataMapper/lib/sql/formulaQueryBuilderFromString.ts

@ -27,18 +27,18 @@ export default function formulaQueryBuilder(tree, alias, knex, aliasToColumn = {
return fn(pt.arguments[0], a, prevBinaryOp) return fn(pt.arguments[0], a, prevBinaryOp)
} }
break; break;
case 'AVG': // case 'AVG':
if (pt.arguments.length > 1) { // if (pt.arguments.length > 1) {
return fn({ // return fn({
type: 'BinaryExpression', // type: 'BinaryExpression',
operator: '/', // operator: '/',
left: {...pt, callee: {name: 'SUM'}}, // left: {...pt, callee: {name: 'SUM'}},
right: {type: 'Literal', value: pt.arguments.length} // right: {type: 'Literal', value: pt.arguments.length}
}, a, prevBinaryOp) // }, a, prevBinaryOp)
} else { // } else {
return fn(pt.arguments[0], a, prevBinaryOp) // return fn(pt.arguments[0], a, prevBinaryOp)
} // }
break; // break;
case 'CONCAT': case 'CONCAT':
if (knex.clientType() === 'sqlite3') { if (knex.clientType() === 'sqlite3') {
if (pt.arguments.length > 1) { if (pt.arguments.length > 1) {
@ -54,7 +54,7 @@ export default function formulaQueryBuilder(tree, alias, knex, aliasToColumn = {
} }
break; break;
default: { default: {
const res = mapFunctionName({pt, knex, alias, aliasToCol: aliasToColumn, fn, colAlias}) const res = mapFunctionName({pt, knex, alias, a, aliasToCol: aliasToColumn, fn, colAlias, prevBinaryOp})
if (res) return res; if (res) return res;
} }
break break
@ -70,6 +70,17 @@ export default function formulaQueryBuilder(tree, alias, knex, aliasToColumn = {
pt.operator = '=' pt.operator = '='
} }
if (pt.operator === '/') {
pt.left = {
callee: {name: 'FLOAT'},
type: 'CallExpression',
arguments: [
pt.left
]
}
}
const query = knex.raw(`${fn(pt.left, null, pt.operator).toQuery()} ${pt.operator} ${fn(pt.right, null, pt.operator).toQuery()}${colAlias}`) const query = knex.raw(`${fn(pt.left, null, pt.operator).toQuery()} ${pt.operator} ${fn(pt.right, null, pt.operator).toQuery()}${colAlias}`)
if (prevBinaryOp && pt.operator !== prevBinaryOp) { if (prevBinaryOp && pt.operator !== prevBinaryOp) {
query.wrap('(', ')') query.wrap('(', ')')

15
packages/nocodb/src/lib/dataMapper/lib/sql/functionMappings/commonFns.ts

@ -31,4 +31,19 @@ export default {
OR: (args: MapFnArgs) => { OR: (args: MapFnArgs) => {
return args.knex.raw(`${args.knex.raw(`${args.pt.arguments.map(ar => args.fn(ar).toQuery()).join(' OR ')}`).wrap('(', ')').toQuery()}${args.colAlias}`) return args.knex.raw(`${args.knex.raw(`${args.pt.arguments.map(ar => args.fn(ar).toQuery()).join(' OR ')}`).wrap('(', ')').toQuery()}${args.colAlias}`)
}, },
AVG: (args: MapFnArgs) => {
if (args.pt.arguments.length > 1) {
return args.fn({
type: 'BinaryExpression',
operator: '/',
left: {...args.pt, callee: {name: 'SUM'}},
right: {type: 'Literal', value: args.pt.arguments.length}
}, args.a, args.prevBinaryOp)
} else {
return args.fn(args.pt.arguments[0], args.a, args.prevBinaryOp)
}
},
FLOAT: (args: MapFnArgs) => {
return args.fn(args.pt?.arguments?.[0]).wrap('(',')');
}
} }

4
packages/nocodb/src/lib/dataMapper/lib/sql/functionMappings/mssql.ts

@ -52,6 +52,8 @@ const mssql = {
return args.knex.raw(`CASE WHEN ISNUMERIC(${args.fn(args.pt.arguments[0]).toQuery()}) = 1 THEN FLOOR(${args.fn(args.pt.arguments[0]).toQuery()}) ELSE 0 END${args.colAlias}`) return args.knex.raw(`CASE WHEN ISNUMERIC(${args.fn(args.pt.arguments[0]).toQuery()}) = 1 THEN FLOOR(${args.fn(args.pt.arguments[0]).toQuery()}) ELSE 0 END${args.colAlias}`)
}, },
MID:'SUBSTR', MID:'SUBSTR',
} FLOAT: (args: MapFnArgs) => {
return args.knex.raw(`CAST(${args.fn(args.pt.arguments[0])} as FLOAT)${args.colAlias}`).wrap('(',')')
}}
export default mssql; export default mssql;

3
packages/nocodb/src/lib/dataMapper/lib/sql/functionMappings/mysql.ts

@ -23,6 +23,9 @@ const mysql2 = {
return args.knex.raw(`SUBSTR(${args.fn(args.pt.arguments[0])},-${args.fn(args.pt.arguments[1])})${args.colAlias}`) return args.knex.raw(`SUBSTR(${args.fn(args.pt.arguments[0])},-${args.fn(args.pt.arguments[1])})${args.colAlias}`)
}, },
MID:'SUBSTR', MID:'SUBSTR',
FLOAT: (args: MapFnArgs) => {
return args.knex.raw(`CAST(${args.fn(args.pt.arguments[0])} as DOUBLE)${args.colAlias}`).wrap('(',')')
}
} }

3
packages/nocodb/src/lib/dataMapper/lib/sql/functionMappings/pg.ts

@ -18,6 +18,9 @@ const pg = {
return args.knex.raw(`REGEXP_REPLACE(COALESCE(${args.fn(args.pt.arguments[0])}::character varying, '0'), '[^0-9]+|\\.[0-9]+' ,'')${args.colAlias}`) return args.knex.raw(`REGEXP_REPLACE(COALESCE(${args.fn(args.pt.arguments[0])}::character varying, '0'), '[^0-9]+|\\.[0-9]+' ,'')${args.colAlias}`)
}, },
MID: 'SUBSTR', MID: 'SUBSTR',
FLOAT: (args: MapFnArgs) => {
return args.knex.raw(`CAST(${args.fn(args.pt.arguments[0])} as DOUBLE PRECISION)${args.colAlias}`).wrap('(',')')
}
} }

3
packages/nocodb/src/lib/dataMapper/lib/sql/functionMappings/sqlite.ts

@ -33,6 +33,9 @@ const sqlite3 = {
return args.knex.raw(`SUBSTR(${args.fn(args.pt.arguments[0])},-${args.fn(args.pt.arguments[1])})${args.colAlias}`) return args.knex.raw(`SUBSTR(${args.fn(args.pt.arguments[0])},-${args.fn(args.pt.arguments[1])})${args.colAlias}`)
}, },
MID: 'SUBSTR', MID: 'SUBSTR',
FLOAT: (args: MapFnArgs) => {
return args.knex.raw(`CAST(${args.fn(args.pt.arguments[0])} as FLOAT)${args.colAlias}`).wrap('(',')')
}
} }

8
packages/nocodb/src/lib/dataMapper/lib/sql/mapFunctionName.ts

@ -10,13 +10,17 @@ export interface MapFnArgs {
aliasToCol: { [alias: string]: string }, aliasToCol: { [alias: string]: string },
knex: XKnex, knex: XKnex,
alias: string, alias: string,
fn: (...args: any) => QueryBuilder, a?: string,
colAlias:string fn: (...args: any) => QueryBuilder | any,
colAlias: string,
prevBinaryOp?: any
} }
const mapFunctionName = (args: MapFnArgs): any => { const mapFunctionName = (args: MapFnArgs): any => {
const name = args.pt.callee.name; const name = args.pt.callee.name;
let val; let val;
switch (args.knex.clientType()) { switch (args.knex.clientType()) {
case 'mysql': case 'mysql':
case 'mysql2': case 'mysql2':

Loading…
Cancel
Save