From fc21e1dec5021ab1518f8418108ce8629420a73c Mon Sep 17 00:00:00 2001 From: Dmitry Shachnev Date: Wed, 13 Mar 2024 06:46:37 +0300 Subject: [PATCH] Add support for URLENCODE function (#6831) Fixes #6811. Co-authored-by: Dmitry Shachnev --- .../060.formula/030.string-functions.md | 21 +++++++++++++++++++ packages/nocodb-sdk/src/lib/formulaHelpers.ts | 16 ++++++++++++++ .../src/db/functionMappings/commonFns.ts | 11 ++++++++++ .../tests/db/columns/columnFormula.spec.ts | 10 +++++++++ 4 files changed, 58 insertions(+) diff --git a/packages/noco-docs/docs/070.fields/040.field-types/060.formula/030.string-functions.md b/packages/noco-docs/docs/070.fields/040.field-types/060.formula/030.string-functions.md index 5285182fd3..85e00d4aad 100644 --- a/packages/noco-docs/docs/070.fields/040.field-types/060.formula/030.string-functions.md +++ b/packages/noco-docs/docs/070.fields/040.field-types/060.formula/030.string-functions.md @@ -216,6 +216,27 @@ URL(text) URL('https://www.example.com') => a clickable link for https://www.example.com ``` +## URLENCODE +The URLENCODE function percent-encodes special characters in a string so it can +be substituted as a query parameter into a URL. + +It is similar to JavaScript `encodeURIComponent()` function, except it encodes +only characters that have a special meaning according to RFC 3986 section 2.2 +and also percent signs and spaces; other characters such as letters from +non-Latin alphabets will not be encoded. Like `encodeURIComponent()`, it should +be used only for encoding URL components, not whole URLs. + +#### Syntax +```plaintext +URLENCODE(text) +``` + +#### Sample +```plaintext +'https://example.com/q?param=' & URLENCODE('Hello, world') +=> 'https://example.com/q?param=Hello%2C%20world' +``` + ## Related Articles - [Numeric and Logical Operators](015.operators.md) diff --git a/packages/nocodb-sdk/src/lib/formulaHelpers.ts b/packages/nocodb-sdk/src/lib/formulaHelpers.ts index 0ba7e1dc54..b935faa93d 100644 --- a/packages/nocodb-sdk/src/lib/formulaHelpers.ts +++ b/packages/nocodb-sdk/src/lib/formulaHelpers.ts @@ -1056,6 +1056,22 @@ export const formulas: Record = { examples: ['URL("https://github.com/nocodb/nocodb")', 'URL({column1})'], returnType: FormulaDataTypes.STRING, }, + URLENCODE: { + docsUrl: + 'https://docs.nocodb.com/fields/field-types/formula/string-functions#urlencode', + + validation: { + args: { + rqd: 1, + type: FormulaDataTypes.STRING, + }, + }, + description: + 'Percent-encode the input parameter for use in URLs', + syntax: 'URLENCODE(str)', + examples: ['URLENCODE("Hello, world") => "Hello%2C%20world"', 'URLENCODE({column1})'], + returnType: FormulaDataTypes.STRING, + }, WEEKDAY: { docsUrl: 'https://docs.nocodb.com/fields/field-types/formula/date-functions#weekday', diff --git a/packages/nocodb/src/db/functionMappings/commonFns.ts b/packages/nocodb/src/db/functionMappings/commonFns.ts index 3a1c267075..79b285acec 100644 --- a/packages/nocodb/src/db/functionMappings/commonFns.ts +++ b/packages/nocodb/src/db/functionMappings/commonFns.ts @@ -384,4 +384,15 @@ export default { builder: knex.raw(`(${valueBuilder} IS NOT NULL)${colAlias}`), }; }, + URLENCODE: async ({ fn, knex, pt, colAlias }: MapFnArgs) => { + const specialCharacters = '% :/?#[]@$&+,;='; + let str = (await fn(pt.arguments[0])).builder; + // Pass the characters as bound parameters to avoid problems with ? sign. + for (const c of specialCharacters) { + str = `REPLACE(${str}, ?, '${encodeURIComponent(c)}')`; + } + return { + builder: knex.raw(`${str} ${colAlias}`, specialCharacters.split('')), + }; + }, }; diff --git a/tests/playwright/tests/db/columns/columnFormula.spec.ts b/tests/playwright/tests/db/columns/columnFormula.spec.ts index b9ca6de3ce..29053a016b 100644 --- a/tests/playwright/tests/db/columns/columnFormula.spec.ts +++ b/tests/playwright/tests/db/columns/columnFormula.spec.ts @@ -143,6 +143,16 @@ const formulaDataByDbType = (context: NcContext, index: number) => { result: ['A Corua (La Corua)', 'Abha', 'Abu Dhabi', 'Acua', 'Ad...'], unSupDbType: ['sqlite3'], }, + { + formula: 'URLENCODE({City})', + result: [ + 'A%20Corua%20(La%20Corua)', + 'Abha', + 'Abu%20Dhabi', + 'Acua', + 'Adana', + ], + }, ]; else return [