fix: db studio multiple schemas support (#3479)

* fix: db studio multiple schemas support

* fix: frontend check (unused urlize flow)
This commit is contained in:
HugoCasa
2024-03-27 23:56:05 +01:00
committed by GitHub
parent c4337d55ae
commit ff2f24a013
5 changed files with 92 additions and 35 deletions
@@ -249,7 +249,12 @@
{
table: {
selectOptions: dbSchemas
? getTablesByResource(dbSchemas, resolvedConfig?.type?.selected)
? await getTablesByResource(
dbSchemas,
resolvedConfig?.type?.selected,
resource.split(':')[1],
$workspaceStore!
)
: [],
loading: false
}
@@ -34,7 +34,7 @@ function makeCountQuery(
} else {
quicksearchCondition += ` (:quicksearch = '' OR 1 = 1)`
}
query += `SELECT COUNT(*) as count FROM \`${table}\``
query += `SELECT COUNT(*) as count FROM ${table}`
break
case 'postgresql':
if (filteredColumns.length > 0) {
@@ -44,7 +44,7 @@ function makeCountQuery(
} else {
quicksearchCondition += `($1 = '' OR 1 = 1)`
}
query += `SELECT COUNT(*) as count FROM "${table}"`
query += `SELECT COUNT(*) as count FROM ${table}`
break
case 'ms_sql_server':
if (filteredColumns.length > 0) {
@@ -28,7 +28,7 @@ function makeSnowflakeSelectQuery(
const filteredColumns = buildVisibleFieldList(columnDefs, 'snowflake')
const selectClause = filteredColumns.join(', ')
query += `SELECT ${selectClause} FROM "${table}"`
query += `SELECT ${selectClause} FROM ${table}`
const quicksearchCondition = [
'LENGTH(?) = 0',
@@ -119,7 +119,7 @@ CASE WHEN :order_by = '${column.field}' AND :is_desc IS true THEN \`${column.fie
', '
)}) LIKE CONCAT('%', :quicksearch, '%'))`
query += `SELECT ${selectClause} FROM \`${table}\``
query += `SELECT ${selectClause} FROM ${table}`
query += ` WHERE ${whereClause ? `${whereClause} AND` : ''} ${quicksearchCondition}`
query += ` ORDER BY ${orderBy}`
query += ` LIMIT :limit OFFSET :offset`
@@ -144,7 +144,7 @@ CASE WHEN :order_by = '${column.field}' AND :is_desc IS true THEN \`${column.fie
query += `SELECT ${filteredColumns
.map((column) => `${column}::text`)
.join(', ')} FROM "${table}"\n`
.join(', ')} FROM ${table}\n`
query += ` WHERE ${whereClause ? `${whereClause} AND` : ''} ${quicksearchCondition}\n`
query += ` ORDER BY ${orderBy}\n`
query += ` LIMIT $1::INT OFFSET $2::INT`
@@ -179,7 +179,8 @@ CASE WHEN :order_by = '${column.field}' AND :is_desc IS true THEN \`${column.fie
if (
column.datatype === 'JSON' ||
column.datatype.startsWith('STRUCT') ||
column.datatype.startsWith('ARRAY')
column.datatype.startsWith('ARRAY') ||
column.datatype === 'GEOGRAPHY'
) {
return `
(CASE WHEN @order_by = '${column.field}' AND @is_desc = false THEN TO_JSON_STRING(${column.field}) END) ASC,
@@ -197,11 +198,12 @@ CASE WHEN :order_by = '${column.field}' AND :is_desc IS true THEN \`${column.fie
if (
def?.datatype === 'JSON' ||
def?.datatype.startsWith('STRUCT') ||
def?.datatype.startsWith('ARRAY')
def?.datatype.startsWith('ARRAY') ||
def?.datatype === 'GEOGRAPHY'
) {
return `TO_JSON_STRING(${col})`
}
return `${col}`
return `CAST(${col} AS STRING)`
})
.join(',')
quicksearchCondition = ` (@quicksearch = '' OR REGEXP_CONTAINS(CONCAT(${searchClause}), '(?i)' || @quicksearch))`
@@ -1,4 +1,4 @@
import { JobService, Preview } from '$lib/gen'
import { JobService, Preview, ResourceService } from '$lib/gen'
import type { DBSchema, DBSchemas, GraphqlSchema, SQLSchema } from '$lib/stores'
import {
buildClientSchema,
@@ -64,6 +64,10 @@ export async function loadTableMetaData(
let code: string = ''
if (resourceType === 'mysql') {
const resourceObj = await ResourceService.getResourceValue({
workspace,
path: resource.split(':')[1]
})
code = `
SELECT
COLUMN_NAME as field,
@@ -76,7 +80,9 @@ export async function loadTableMetaData(
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = '${table}'
TABLE_NAME = '${table.split('.').reverse()[0]}' AND TABLE_SCHEMA = '${
table.split('.').reverse()[1] ?? resourceObj?.database ?? ''
}'
ORDER BY
ORDINAL_POSITION;
`
@@ -105,7 +111,9 @@ export async function loadTableMetaData(
FROM pg_catalog.pg_enum e
WHERE e.enumtypid = a.atttypid FETCH FIRST ROW ONLY) as IsEnum
FROM pg_catalog.pg_attribute a
WHERE a.attrelid = (SELECT oid FROM pg_catalog.pg_class WHERE relname = '${table}')
WHERE a.attrelid = (SELECT c.oid FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace ns ON c.relnamespace = ns.oid WHERE relname = '${
table.split('.').reverse()[0]
}' AND ns.nspname = '${table.split('.').reverse()[1] ?? 'public'}')
AND a.attnum > 0 AND NOT a.attisdropped
ORDER BY a.attnum;
@@ -138,7 +146,9 @@ ORDER BY
CASE WHEN IS_NULLABLE = 'YES' THEN 'YES' ELSE 'NO' END as IsNullable,
CASE WHEN DATA_TYPE = 'enum' THEN 1 ELSE 0 END as IsEnum
from information_schema.columns
where table_name = '${table}'
where table_name = '${table.split('.').reverse()[0]}' and table_schema = '${
table.split('.').reverse()[1] ?? 'PUBLIC'
}'
order by ORDINAL_POSITION;
`
} else if (resourceType === 'bigquery') {
@@ -151,7 +161,7 @@ ORDER BY
IS_NULLABLE as IsNullable,
false as IsEnum
FROM
test_dataset.INFORMATION_SCHEMA.COLUMNS c
${table.split('.')[0]}.INFORMATION_SCHEMA.COLUMNS c
LEFT JOIN
test_dataset.INFORMATION_SCHEMA.KEY_COLUMN_USAGE p
on c.table_name = p.table_name AND c.column_name = p.COLUMN_NAME
@@ -674,34 +684,75 @@ export function getPrimaryKeys(tableMetadata?: TableMetadata): string[] {
return r ?? []
}
export function getTablesByResource(
export async function getTablesByResource(
schema: Partial<Record<string, DBSchema>>,
dbType: DbType | undefined
): string[] {
dbType: DbType | undefined,
resourcePath: string,
workspace: string
): Promise<string[]> {
const s = Object.values(schema)?.[0]
switch (dbType) {
case 'postgresql':
case 'mysql':
case 'ms_sql_server':
case 'snowflake':
return Object.entries(s?.schema ?? {}).reduce((acc: string[], [k, v]) => {
acc.push(...Object.keys(v ?? {}))
return acc
}, [])
case 'bigquery': {
case 'ms_sql_server': {
const paths: string[] = []
for (const key in s?.schema) {
if (s?.schema.hasOwnProperty(key)) {
const subObj = s?.schema[key]
for (const subKey in subObj) {
if (subObj.hasOwnProperty(subKey)) {
paths.push(`${key}.${subKey}`)
}
for (const subKey in s.schema[key]) {
if (key === 'dbo') {
paths.push(`${subKey}`)
}
}
}
return paths
}
case 'mysql': {
const resourceObj = await ResourceService.getResourceValue({
workspace,
path: resourcePath
})
const paths: string[] = []
for (const key in s?.schema) {
for (const subKey in s.schema[key]) {
if (key === resourceObj?.database) {
paths.push(`${subKey}`)
} else {
paths.push(`${key}.${subKey}`)
}
}
}
return paths
}
case 'snowflake': {
const paths: string[] = []
for (const key in s?.schema) {
for (const subKey in s.schema[key]) {
if (key === 'PUBLIC') {
paths.push(`${subKey}`)
} else {
paths.push(`${key}.${subKey}`)
}
}
}
return paths
}
case 'postgresql': {
const paths: string[] = []
for (const key in s?.schema) {
for (const subKey in s.schema[key]) {
if (key === 'public') {
paths.push(`${subKey}`)
} else {
paths.push(`${key}.${subKey}`)
}
}
}
return paths
}
case 'bigquery': {
const paths: string[] = []
for (const key in s?.schema) {
for (const subKey in s.schema[key]) {
paths.push(`${key}.${subKey}`)
}
}
return paths
}
@@ -12,7 +12,6 @@
import ShareModal from '$lib/components/ShareModal.svelte'
import { runFormStore, userStore, workspaceStore } from '$lib/stores'
import { sendUserToast } from '$lib/toast'
import Urlize from '$lib/components/Urlize.svelte'
import DeployWorkspaceDrawer from '$lib/components/DeployWorkspaceDrawer.svelte'
import SavedInputs from '$lib/components/SavedInputs.svelte'
import {