mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-31 00:13:53 +00:00
fix: db studio multiple schemas support (#3479)
* fix: db studio multiple schemas support * fix: frontend check (unused urlize flow)
This commit is contained in:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user