fix(postgres): handle PostgreSQL views
This commit is contained in:
parent
2999d9c56f
commit
484d20922a
|
|
@ -269,10 +269,10 @@ function handleOptionsUpdate(options: SchemaDiffCompareOptions) {
|
|||
* Views and materialized views need the object_type parameter so the
|
||||
* backend can call DBMS_METADATA.GET_DDL with the correct type. */
|
||||
function isViewOrMaterializedView(tableType: string): ObjectSourceKind | undefined {
|
||||
switch (tableType.toUpperCase()) {
|
||||
switch (tableType.toUpperCase().replace(/\s+/g, "_")) {
|
||||
case "VIEW":
|
||||
return "VIEW";
|
||||
case "MATERIALIZED VIEW":
|
||||
case "MATERIALIZED_VIEW":
|
||||
return "MATERIALIZED_VIEW";
|
||||
default:
|
||||
return undefined;
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ async function del<T>(url: string): Promise<T> {
|
|||
return res.json();
|
||||
}
|
||||
|
||||
function qs(params: Record<string, string | number | undefined>): string {
|
||||
function qs(params: Record<string, string | number | boolean | undefined>): string {
|
||||
const sp = new URLSearchParams();
|
||||
for (const [k, v] of Object.entries(params)) {
|
||||
if (v !== undefined && v !== null) sp.set(k, String(v));
|
||||
|
|
@ -564,7 +564,7 @@ export async function listFunctions(connectionId: string, database: string, sche
|
|||
}
|
||||
|
||||
export async function listSequences(connectionId: string, database: string, schema: string, withLastValues: boolean): Promise<SequenceInfo[]> {
|
||||
return get(`/api/schema/sequences?${qs({ connection_id: connectionId, database, schema, with_last_values: withLastValues ? 1 : 0 })}`);
|
||||
return get(`/api/schema/sequences?${qs({ connection_id: connectionId, database, schema, with_last_values: withLastValues })}`);
|
||||
}
|
||||
|
||||
export async function listRules(connectionId: string, database: string, schema: string): Promise<RuleInfo[]> {
|
||||
|
|
|
|||
|
|
@ -578,8 +578,8 @@ pub async fn export_database_sql_core(
|
|||
}
|
||||
|
||||
// 7. Separate tables and views
|
||||
let mut tables: Vec<_> = all_tables.iter().filter(|t| t.table_type != "VIEW").collect();
|
||||
let views: Vec<_> = all_tables.iter().filter(|t| t.table_type == "VIEW").collect();
|
||||
let mut tables: Vec<_> = all_tables.iter().filter(|t| !t.table_type.contains("VIEW")).collect();
|
||||
let views: Vec<_> = all_tables.iter().filter(|t| t.table_type.contains("VIEW")).collect();
|
||||
let postgres_sequences = if request.include_structure && matches!(db_type, DatabaseType::Postgres) {
|
||||
match list_postgres_export_sequences(
|
||||
state,
|
||||
|
|
|
|||
|
|
@ -1153,7 +1153,7 @@ pub async fn completion_assistant_search(
|
|||
let table_type: String = row.get(2);
|
||||
candidates.push(CompletionAssistantCandidate {
|
||||
name: row.get(0),
|
||||
kind: if table_type == "VIEW" {
|
||||
kind: if table_type.contains("VIEW") {
|
||||
CompletionAssistantCandidateKind::View
|
||||
} else {
|
||||
CompletionAssistantCandidateKind::Table
|
||||
|
|
|
|||
|
|
@ -432,6 +432,8 @@ fn build_sqlserver_alter_view_sql(schema: Option<&str>, name: &str, source: &str
|
|||
fn parse_object_source_kind(value: &str) -> Option<ObjectSourceKind> {
|
||||
if value.eq_ignore_ascii_case("VIEW") {
|
||||
Some(ObjectSourceKind::View)
|
||||
} else if value.eq_ignore_ascii_case("MATERIALIZED VIEW") || value.eq_ignore_ascii_case("MATERIALIZED_VIEW") {
|
||||
Some(ObjectSourceKind::MaterializedView)
|
||||
} else if value.eq_ignore_ascii_case("PROCEDURE") {
|
||||
Some(ObjectSourceKind::Procedure)
|
||||
} else if value.eq_ignore_ascii_case("FUNCTION") {
|
||||
|
|
|
|||
|
|
@ -1779,9 +1779,7 @@ async fn completion_assistant_fallback_core(
|
|||
)
|
||||
.await?;
|
||||
for table in tables {
|
||||
let kind = if table.table_type.eq_ignore_ascii_case("VIEW")
|
||||
|| table.table_type.eq_ignore_ascii_case("MATERIALIZED_VIEW")
|
||||
{
|
||||
let kind = if table.table_type.to_uppercase().contains("VIEW") {
|
||||
db::CompletionAssistantCandidateKind::View
|
||||
} else {
|
||||
db::CompletionAssistantCandidateKind::Table
|
||||
|
|
@ -2819,7 +2817,9 @@ pub fn postgres_object_source_sql(schema: &str, name: &str, kind: &db::ObjectSou
|
|||
match kind {
|
||||
db::ObjectSourceKind::View | db::ObjectSourceKind::MaterializedView => {
|
||||
format!(
|
||||
"SELECT pg_get_viewdef(c.oid, 0) \
|
||||
"SELECT CASE WHEN c.relkind = 'm' THEN format('CREATE MATERIALIZED VIEW %I.%I AS ', n.nspname, c.relname) || regexp_replace(pg_get_viewdef(c.oid, 0), ';[[:space:]]*$', '') || CASE WHEN c.relispopulated THEN ' WITH DATA' ELSE ' WITH NO DATA' END \
|
||||
ELSE format('CREATE OR REPLACE VIEW %I.%I AS ', n.nspname, c.relname) || pg_get_viewdef(c.oid, 0) \
|
||||
END \
|
||||
FROM pg_catalog.pg_class c \
|
||||
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace \
|
||||
WHERE n.nspname = {} AND c.relname = {} AND c.relkind IN ('v','m') \
|
||||
|
|
@ -3178,7 +3178,7 @@ mod object_source_tests {
|
|||
fn builds_postgres_object_source_sql_for_views_and_functions() {
|
||||
assert_eq!(
|
||||
postgres_object_source_sql("public", "active_users", &ObjectSourceKind::View),
|
||||
"SELECT pg_get_viewdef(c.oid, 0) FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = 'public' AND c.relname = 'active_users' AND c.relkind IN ('v','m') ORDER BY c.oid LIMIT 1"
|
||||
"SELECT CASE WHEN c.relkind = 'm' THEN format('CREATE MATERIALIZED VIEW %I.%I AS ', n.nspname, c.relname) || regexp_replace(pg_get_viewdef(c.oid, 0), ';[[:space:]]*$', '') || CASE WHEN c.relispopulated THEN ' WITH DATA' ELSE ' WITH NO DATA' END ELSE format('CREATE OR REPLACE VIEW %I.%I AS ', n.nspname, c.relname) || pg_get_viewdef(c.oid, 0) END FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = 'public' AND c.relname = 'active_users' AND c.relkind IN ('v','m') ORDER BY c.oid LIMIT 1"
|
||||
);
|
||||
assert_eq!(
|
||||
postgres_object_source_sql("public", "recalc_score", &ObjectSourceKind::Function),
|
||||
|
|
@ -3192,6 +3192,7 @@ mod object_source_tests {
|
|||
|
||||
assert!(!sql.contains("::regclass"));
|
||||
assert!(sql.contains("pg_get_viewdef(c.oid, 0)"));
|
||||
assert!(sql.contains("format('CREATE OR REPLACE VIEW %I.%I AS ', n.nspname, c.relname)"));
|
||||
assert!(sql.contains("n.nspname = 'tenant''s schema'"));
|
||||
assert!(sql.contains("c.relname = 'active users'"));
|
||||
assert!(sql.contains("c.relkind IN ('v','m')"));
|
||||
|
|
|
|||
|
|
@ -263,25 +263,25 @@ fn diff_schema(options: &SchemaDiffPreparationOptions) -> Vec<TableDiff> {
|
|||
let source_table_names: Vec<String> = options
|
||||
.source_tables
|
||||
.iter()
|
||||
.filter(|table| table.table_type != "VIEW")
|
||||
.filter(|table| !table.table_type.contains("VIEW"))
|
||||
.map(|table| table.name.clone())
|
||||
.collect();
|
||||
let target_table_names: Vec<String> = options
|
||||
.target_tables
|
||||
.iter()
|
||||
.filter(|table| table.table_type != "VIEW")
|
||||
.filter(|table| !table.table_type.contains("VIEW"))
|
||||
.map(|table| table.name.clone())
|
||||
.collect();
|
||||
let source_view_names: Vec<String> = options
|
||||
.source_tables
|
||||
.iter()
|
||||
.filter(|table| table.table_type == "VIEW")
|
||||
.filter(|table| table.table_type.contains("VIEW"))
|
||||
.map(|table| table.name.clone())
|
||||
.collect();
|
||||
let target_view_names: Vec<String> = options
|
||||
.target_tables
|
||||
.iter()
|
||||
.filter(|table| table.table_type == "VIEW")
|
||||
.filter(|table| table.table_type.contains("VIEW"))
|
||||
.map(|table| table.name.clone())
|
||||
.collect();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue