Files
supabase/apps/studio/components/interfaces/Database/CronJobs/CronJobs.utils.ts
T
Ivan VasilovandJoshen Lim fd3309c886 feat: UI for pg-cron (#29291)
* Add crons option in the database menu.

* Add react-hook-form to the studio package.json.

* Refactor the functionSelector to be used by other features.

* Add the bulk of the functionality for the cron UI. Some of the code is copy-pasted from functions feature, needs to be cleaned before merging.

* Tons of changes, the Create Cron sheet works now.

* Added some more functionality for the cronjob feature.

* Convert the Cron table to a listing with cards.

* Add click-to-copy in the Auth Hooks feature.

* Remove extra prop.

* Fix type errors.

* Fix some random issues. Fix the tests.

* Fix the tests.

* Add a style for disabled radio button item.

* Make the default SQL snippet. Handle the case pg_net is not installed.

* Fix the heading and save button when creating a new cron job.

* Change the name of the custom label in the schedule dropdown.

* Minor fixes.

* Rename all mentions of cronjobs to cron jobs.

* Always show the cron jobs link.

* Rename the link from crons to cron-jobs.

* Fix the disabled state for the stacked radio group.

* More minor fixes.

* More small fixes.

* Fix the tests.

* Minor UI tweaks

* More minor tweaks

* Add padding bottom

* Add feature flag for the cron ui.

* Fix the SQL function option.

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2024-10-03 15:11:17 -02:30

107 lines
3.4 KiB
TypeScript

import { CronJobType } from './CreateCronJobSheet'
import { HTTPHeader, HTTPParameter } from './CronJobs.constants'
export const buildCronQuery = (name: string, schedule: string, command: string) => {
return `select cron.schedule('${name}','${schedule}',${command});`
}
export const buildHttpRequestCommand = (
method: 'GET' | 'POST',
url: string,
headers: HTTPHeader[],
body: HTTPParameter[],
timeout: number
) => {
return `$$
select
net.${method === 'GET' ? 'http_get' : 'http_post'}(
url:='${url}',
headers:=jsonb_build_object(${headers.map((v) => `'${v.name}', '${v.value}'`).join(', ')}),
body:=jsonb_build_object(${body.map((v) => `'${v.name}', '${v.value}'`).join(', ')}),
timeout_milliseconds:=${timeout}
);
$$`
}
export const DEFAULT_CRONJOB_COMMAND = {
type: 'sql_snippet',
snippet: '',
} as const
export const parseCronJobCommand = (originalCommand: string): CronJobType => {
const command = originalCommand
.replaceAll('$$', ' ')
.replaceAll(/\n/g, ' ')
.replaceAll(/\s+/g, ' ')
.trim()
if (command.toLocaleLowerCase().startsWith('select net.')) {
const matches =
command.match(
/select net\.([^']+)\(\s*url:='([^']+)',\s*headers:=jsonb_build_object\(([^)]*)\),\s*body:=jsonb_build_object\(([^]*)\s*\),\s*timeout_milliseconds:=(\d+) \)/i
) || []
// convert the header string to array of objects, clean up the values, trim them of spaces and remove the quotation marks at start and end
const headers = (matches[3] || '').split(',').map((s) => s.trim().replace(/^'|'$/g, ''))
const headersObjs: { name: string; value: string }[] = []
for (let i = 0; i < headers.length; i += 2) {
if (headers[i] && headers[i].length > 0) {
headersObjs.push({ name: headers[i], value: headers[i + 1] })
}
}
// convert the parameter string to array of objects, clean up the values, trim them of spaces and remove the quotation marks at start and end
const parameters = (matches[4] || '').split(',').map((s) => s.trim().replace(/^'|'$/g, ''))
const parametersObjs: { name: string; value: string }[] = []
for (let i = 0; i < parameters.length; i += 2) {
if (parameters[i] && parameters[i].length > 0) {
parametersObjs.push({ name: parameters[i], value: parameters[i + 1] })
}
}
const url = matches[2] || ''
if (url.includes('.supabase.') && url.includes('/functions/v1/')) {
return {
type: 'edge_function',
method: matches[1] === 'http_get' ? 'GET' : 'POST',
edgeFunctionName: url,
httpHeaders: headersObjs,
httpParameters: parametersObjs,
timeoutMs: +matches[5] ?? 1000,
}
}
return {
type: 'http_request',
method: matches[1] === 'http_get' ? 'GET' : 'POST',
endpoint: url,
httpHeaders: headersObjs,
httpParameters: parametersObjs,
timeoutMs: +matches[5] ?? 1000,
}
}
if (command.toLocaleLowerCase().startsWith('call ')) {
const [schemaName, functionName] = command
.replace('CALL ', '')
.replace('()', '')
.trim()
.split('.')
return {
type: 'sql_function',
schema: schemaName,
functionName: functionName,
}
}
if (command.length > 0) {
return {
type: 'sql_snippet',
snippet: originalCommand,
}
}
return DEFAULT_CRONJOB_COMMAND
}