| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- import { SupaTable } from '@/components/grid/types'
- import { Lint } from '@/data/lint/lint-query'
- export const getEntityLintDetails = (
- entityName: string,
- lintName: string,
- lintLevels: ('ERROR' | 'WARN' | 'INFO')[],
- lints: Lint[],
- schema: string
- ): { hasLint: boolean; count: number; matchingLint: Lint | null } => {
- const matchingLint =
- lints?.find(
- (lint) =>
- lint?.metadata?.name === entityName &&
- lint?.metadata?.schema === schema &&
- lint?.name === lintName &&
- lintLevels.includes(lint?.level)
- ) || null
- return {
- hasLint: matchingLint !== null,
- count: matchingLint ? 1 : 0,
- matchingLint,
- }
- }
- export const getTablePoliciesUrl = (
- projectRef: string | undefined,
- schema: string | undefined,
- name: string | undefined
- ): string => {
- return `/project/${projectRef ?? ''}/auth/policies?search=${encodeURIComponent(
- name ?? ''
- )}&schema=${encodeURIComponent(schema ?? '')}`
- }
- export const formatTableRowsToSQL = (table: SupaTable, rows: any[]) => {
- if (rows.length === 0) return ''
- const columns = table.columns.map((col) => `"${col.name}"`).join(', ')
- const valuesSets = rows
- .map((row) => {
- const filteredRow = { ...row }
- if ('idx' in filteredRow) delete filteredRow.idx
- const values = Object.entries(filteredRow).map(([key, val]) => {
- const { dataType, format } = table.columns.find((col) => col.name === key) ?? {}
- // We only check for NULL, array and JSON types, everything else we stringify
- // given that Postgres can implicitly cast the right type based on the column type
- // For string types, we need to deal with escaping single quotes
- const stringFormats = ['text', 'varchar']
- if (val === null) {
- return 'null'
- } else if (dataType === 'ARRAY') {
- const array = Array.isArray(val) ? val : JSON.parse(val as string)
- return `${formatArrayForSql(array as unknown[])}`
- } else if (format?.includes('json')) {
- return `${JSON.stringify(val).replace(/\\"/g, '"').replace(/'/g, "''").replace('"', "'").replace(/.$/, "'")}`
- } else if (
- typeof format === 'string' &&
- typeof val === 'string' &&
- stringFormats.includes(format)
- ) {
- return `'${val.replaceAll("'", "''")}'`
- } else if (typeof val === 'number' || typeof val === 'boolean') {
- return `${val}`
- } else if (typeof val === 'string') {
- return `'${val.replaceAll("'", "''")}'`
- } else {
- return `'${val}'`
- }
- })
- return `(${values.join(', ')})`
- })
- .join(', ')
- return `INSERT INTO "${table.schema}"."${table.name}" (${columns}) VALUES ${valuesSets};`
- }
- /**
- * Generate a random tag for dollar-quoting of SQL strings
- *
- * @return A random tag in the format `$tag$`
- */
- const generateRandomTag = (): `$${string}$` => {
- const inner = Math.random().toString(36).substring(2, 15)
- // Ensure the tag starts with a character not a digit to avoid conflicts with
- // Postgres parameter syntax
- return `$x${inner}$`
- }
- /**
- * Wrap a string in dollar-quote tags, ensuring the tag does not appear in the string
- *
- * @throws Error if unable to generate a unique dollar-quote tag after multiple attempts
- */
- const safeDollarQuote = (str: string): string => {
- let tag = generateRandomTag()
- let attempts = 0
- const maxAttempts = 100
- while (str.includes(tag)) {
- if (attempts >= maxAttempts) {
- throw new Error('Unable to generate a unique dollar-quote tag after multiple attempts.')
- }
- attempts++
- tag = generateRandomTag()
- }
- return `${tag}${str}${tag}`
- }
- const formatArrayForSql = (arr: unknown[]): string => {
- let result = 'ARRAY['
- arr.forEach((item, index) => {
- if (Array.isArray(item)) {
- result += formatArrayForSql(item)
- } else if (typeof item === 'string') {
- result += `'${item.replaceAll("'", "''")}'`
- } else if (!!item && typeof item === 'object') {
- result += `${safeDollarQuote(JSON.stringify(item))}::json`
- } else {
- result += `${item}`
- }
- if (index < arr.length - 1) {
- result += ','
- }
- })
- result += ']'
- return result
- }
|