_id is free

This commit is contained in:
Priec
2026-08-08 00:19:33 +02:00
parent 0d78556428
commit 5be1a5c661
9 changed files with 58 additions and 24 deletions

2
client

Submodule client updated: 46e40cf1f9...8538beba2a

View File

@@ -200,6 +200,17 @@ message TableDefinitionResponse {
// Describes the tree of all profiles and their tables. // Describes the tree of all profiles and their tables.
message ProfileTreeResponse { message ProfileTreeResponse {
// One link: the table it points at, and the column carrying it.
message Dependency {
// Table being referenced.
string table_name = 1;
// Column holding the reference, named by whoever declared the link. This
// is what identifies the link, since a table may point at one target
// several times.
string column_name = 2;
}
// Table entry in a profile. // Table entry in a profile.
message Table { message Table {
// Internal ID from table_definitions.id (metadata record). // Internal ID from table_definitions.id (metadata record).
@@ -208,8 +219,9 @@ message ProfileTreeResponse {
// Table name within the profile (schema). // Table name within the profile (schema).
string name = 2; string name = 2;
// Other tables this one references (based on link definitions only). // Links this table declares. One entry per link, so a table that names the
repeated string depends_on = 3; // same target twice appears twice.
repeated Dependency depends_on = 3;
// Columns whose values make up the human-readable row label, in order. // Columns whose values make up the human-readable row label, in order.
repeated string row_display_columns = 4; repeated string row_display_columns = 4;

Binary file not shown.

View File

@@ -173,8 +173,20 @@ pub struct ProfileTreeResponse {
} }
/// Nested message and enum types in `ProfileTreeResponse`. /// Nested message and enum types in `ProfileTreeResponse`.
pub mod profile_tree_response { pub mod profile_tree_response {
/// Table entry in a profile. /// One link: the table it points at, and the column carrying it.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct Dependency {
/// Table being referenced.
#[prost(string, tag = "1")]
pub table_name: ::prost::alloc::string::String,
/// Column holding the reference, named by whoever declared the link. This
/// is what identifies the link, since a table may point at one target
/// several times.
#[prost(string, tag = "2")]
pub column_name: ::prost::alloc::string::String,
}
/// Table entry in a profile.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Table { pub struct Table {
/// Internal ID from table_definitions.id (metadata record). /// Internal ID from table_definitions.id (metadata record).
#[prost(int64, tag = "1")] #[prost(int64, tag = "1")]
@@ -182,9 +194,10 @@ pub mod profile_tree_response {
/// Table name within the profile (schema). /// Table name within the profile (schema).
#[prost(string, tag = "2")] #[prost(string, tag = "2")]
pub name: ::prost::alloc::string::String, pub name: ::prost::alloc::string::String,
/// Other tables this one references (based on link definitions only). /// Links this table declares. One entry per link, so a table that names the
#[prost(string, repeated, tag = "3")] /// same target twice appears twice.
pub depends_on: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, #[prost(message, repeated, tag = "3")]
pub depends_on: ::prost::alloc::vec::Vec<Dependency>,
/// Columns whose values make up the human-readable row label, in order. /// Columns whose values make up the human-readable row label, in order.
#[prost(string, repeated, tag = "4")] #[prost(string, repeated, tag = "4")]
pub row_display_columns: ::prost::alloc::vec::Vec< pub row_display_columns: ::prost::alloc::vec::Vec<

View File

@@ -13,6 +13,10 @@ pub struct RelationshipHop {
pub struct RelationshipLink { pub struct RelationshipLink {
pub source_table: String, pub source_table: String,
pub target_table: String, pub target_table: String,
/// The column carrying the link, which is the name it was given. A table
/// may link to one target several times, so the target's name does not
/// identify the column.
pub fk_column: String,
} }
pub fn resolve_relationship_path( pub fn resolve_relationship_path(
@@ -53,7 +57,7 @@ pub fn resolve_relationship_path(
from_table: table.clone(), from_table: table.clone(),
to_table: next.to_string(), to_table: next.to_string(),
fk_source_table: link.source_table.clone(), fk_source_table: link.source_table.clone(),
fk_column: format!("{}_id", link.target_table), fk_column: link.fk_column.clone(),
}); });
if next == end { if next == end {
match_depth = Some(next_path.len()); match_depth = Some(next_path.len());

2
server

Submodule server updated: 9b5956ce99...79e64a2bd5

View File

@@ -63,7 +63,7 @@ pub(crate) fn render_submission_error(message: &str) -> String {
mod tests { mod tests {
use super::*; use super::*;
use crate::{ use crate::{
pages::add_table::draft::{LinkMode, TableDraft}, pages::add_table::draft::TableDraft,
schema::{ColumnDefinition, MoneyMode}, schema::{ColumnDefinition, MoneyMode},
}; };
@@ -81,7 +81,6 @@ mod tests {
currency: String::new(), currency: String::new(),
}); });
draft.set_available_relation_tables(vec!["customer".to_string()]); draft.set_available_relation_tables(vec!["customer".to_string()]);
draft.cycle_link_mode(0);
draft.toggle_row_display_candidate(1); draft.toggle_row_display_candidate(1);
AddTablePageState { AddTablePageState {
@@ -103,11 +102,9 @@ mod tests {
// Every part of the draft travels with the next request. // Every part of the draft travels with the next request.
assert!(html.contains(r#"name="column_names" value="number""#)); assert!(html.contains(r#"name="column_names" value="number""#));
assert!(html.contains(r#"name="column_indexed" value="yes""#)); assert!(html.contains(r#"name="column_indexed" value="yes""#));
assert!(html.contains(r#"name="link_tables" value="customer""#)); assert!(html.contains(r#"name="relation_tables" value="customer""#));
assert!(html.contains(r#"name="link_modes" value="optional""#));
assert!(html.contains(r#"name="row_display_columns" value="number""#)); assert!(html.contains(r#"name="row_display_columns" value="number""#));
// The preview shows the schema as it will exist. // The preview shows the schema as it will exist.
assert!(html.contains("customer_id"));
assert!(html.contains("BIGSERIAL")); assert!(html.contains("BIGSERIAL"));
assert!(html.contains("TIMESTAMPTZ")); assert!(html.contains("TIMESTAMPTZ"));
} }
@@ -208,12 +205,4 @@ mod tests {
assert!(html.contains("The backend is unreachable.")); assert!(html.contains("The backend is unreachable."));
} }
#[test]
fn a_link_mode_is_shown_on_the_button_that_cycles_it() {
let html = render_builder(&page());
assert!(html.contains(r#""action": "cycle-link", "index": "0""#));
assert!(html.contains("mode-optional"));
assert_eq!(LinkMode::Optional.label(), "optional");
}
} }

View File

@@ -68,7 +68,15 @@ pub(crate) async fn load_admin_page(
.iter() .iter()
.map(|table| TableView { .map(|table| TableView {
name: table.name.clone(), name: table.name.clone(),
depends_on: table.depends_on.clone(), // One entry per link, named by the column carrying it, so a
// table pointing at one target twice reads as two links.
depends_on: table
.depends_on
.iter()
.map(|dependency| {
format!("{} ({})", dependency.table_name, dependency.column_name)
})
.collect(),
row_display_columns: table.row_display_columns.clone(), row_display_columns: table.row_display_columns.clone(),
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>()

View File

@@ -112,7 +112,15 @@ pub(crate) async fn load_page(
.map(|table| TableSummary { .map(|table| TableSummary {
name: table.name.clone(), name: table.name.clone(),
table_kind: table.table_kind.clone(), table_kind: table.table_kind.clone(),
depends_on: table.depends_on.clone(), // One entry per link, named by the column carrying it, so a
// table pointing at one target twice reads as two links.
depends_on: table
.depends_on
.iter()
.map(|dependency| {
format!("{} ({})", dependency.table_name, dependency.column_name)
})
.collect(),
row_display_columns: table.row_display_columns.clone(), row_display_columns: table.row_display_columns.clone(),
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>()