// common/proto/table_definition.proto syntax = "proto3"; package komp_ac.table_definition; import "common.proto"; // The TableDefinition service manages the entire lifecycle of user-defined // tables (stored as both metadata and physical PostgreSQL tables) inside // logical "profiles" (schemas). Each table has stored structure, links, and // validation rules. service TableDefinition { rpc GetModuleConfiguration(GetModuleConfigurationRequest) returns (ModuleConfiguration); rpc SetModuleConfiguration(SetModuleConfigurationRequest) returns (ModuleConfiguration); // Creates a new table (and schema if missing) with system columns, // linked-table foreign keys, user-defined columns, and optional indexes. // Also inserts metadata and default validation rules. Entirely transactional. rpc PostTableDefinition(PostTableDefinitionRequest) returns (TableDefinitionResponse); // Explicitly creates the optional administrator-managed exchange-rate table // in an existing profile. The server owns its core shape and constraints. rpc CreateCustomExchangeRatesTable(CreateCustomExchangeRatesTableRequest) returns (CreateCustomExchangeRatesTableResponse); // Creates a regular user-table bundle from the restricted komp_ac_fields // contract embedded in a Typst invoice template. This is invoked explicitly // by the user; templates do not provision tables merely by existing. rpc CreateInvoiceTemplateTable(CreateInvoiceTemplateTableRequest) returns (CreateInvoiceTemplateTableResponse); // Applies the administrator-reviewed, explicitly typed table bundle and // exact komp_ac_fields bindings for an imported Typst template. rpc ApplyInvoiceTemplateTable(ApplyInvoiceTemplateTableRequest) returns (CreateInvoiceTemplateTableResponse); // Appends new user-defined columns to an existing table. // Existing columns, links, and table logic are never changed by this call. rpc AddTableColumns(AddTableColumnsRequest) returns (TableDefinitionResponse); // Atomically removes selected columns and appends new columns to an empty // dynamic table. Column identities come from GetProfileDetails. The call is // rejected after any row, including a soft-deleted row, has been stored. rpc PutTableDefinition(PutTableDefinitionRequest) returns (PutTableDefinitionResponse); // Lists all profiles (schemas) and their tables with declared dependencies. // This provides a tree-like overview of table relationships. rpc GetProfileTree(komp_ac.common.Empty) returns (ProfileTreeResponse); // Lists the tables visible in one data-entry scope. When profile_name is // absent, only global tables are returned. rpc GetTableCatalog(GetTableCatalogRequest) returns (GetTableCatalogResponse); // Lists every column type a table may declare, along with the SQL type it // maps to. Pure data retrieval - no business logic. rpc ListColumnTypes(komp_ac.common.Empty) returns (ListColumnTypesResponse); // Fetches all tables with their columns and scripts for a specific profile. // Pure data retrieval - no business logic. rpc GetProfileDetails(GetProfileDetailsRequest) returns (GetProfileDetailsResponse); // Copies one complete profile into a new profile without copying table data. rpc CopyProfile(CopyProfileRequest) returns (CopyProfileResponse); // Serializes selected table structure and every required structural dependency. // Dynamic table rows and deployment-local security state are never included. rpc ExportProfileBlueprint(ExportProfileBlueprintRequest) returns (ExportProfileBlueprintResponse); // Reconciles a portable blueprint against a destination profile without writing. rpc PlanProfileBlueprintImport(PlanProfileBlueprintImportRequest) returns (PlanProfileBlueprintImportResponse); // Applies a previously reviewed blueprint plan atomically. The plan hash protects // against both a changed package and destination drift between preview and apply. rpc ImportProfileBlueprint(ImportProfileBlueprintRequest) returns (ImportProfileBlueprintResponse); // Returns the unified append-only history for column and option aliases. rpc GetAliasChangeHistory(GetAliasChangeHistoryRequest) returns (GetAliasChangeHistoryResponse); // Atomically replaces the aliases and presentation order of a table's columns. // Physical column names and identities remain unchanged. rpc SetColumnPresentation(SetColumnPresentationRequest) returns (SetColumnPresentationResponse); // Replaces the columns whose values identify rows to users. This is // presentation metadata and may be changed after rows have been stored. rpc SetRowDisplayColumns(SetRowDisplayColumnsRequest) returns (SetRowDisplayColumnsResponse); // Replaces the user-managed indexes of an existing dynamic table. Physical // indexes are created or dropped even when rows have already been stored. rpc SetTableIndexes(SetTableIndexesRequest) returns (SetTableIndexesResponse); // Changes whether one existing column is required. Enabling the requirement // is rejected while an active row has no value for the column. rpc SetColumnRequired(SetColumnRequiredRequest) returns (SetColumnRequiredResponse); // Replaces the optional user-visible aliases for a fixed-option column. // Stored values remain stable machine values and scripts never depend on labels. rpc SetColumnOptionAliases(SetColumnOptionAliasesRequest) returns (SetColumnOptionAliasesResponse); // Shows or hides one column in bundled data-entry forms. This is presentation // metadata only: hidden columns remain available to data APIs, scripts and // backend calculations. rpc SetColumnFormVisibility(SetColumnFormVisibilityRequest) returns (SetColumnFormVisibilityResponse); // Drops a table and its metadata, then deletes the profile if it becomes empty. rpc DeleteTable(DeleteTableRequest) returns (DeleteTableResponse); // Deletes an entire profile only when none of its user or backend-managed // tables, audit stores, document stores, or accounting stores contain data. rpc DeleteProfile(DeleteProfileRequest) returns (DeleteProfileResponse); } message ModuleScope { oneof target { komp_ac.common.Empty global = 1; string profile_name = 2; } } message GetModuleConfigurationRequest { ModuleScope scope = 1; } message SetModuleConfigurationRequest { ModuleScope scope = 1; repeated string enabled_modules = 2; } message ModuleConfiguration { ModuleScope scope = 1; repeated string available_modules = 2; repeated string selected_modules = 3; repeated string inherited_modules = 4; repeated string effective_modules = 5; } message CreateCustomExchangeRatesTableRequest { string profile_name = 1; } message CreateCustomExchangeRatesTableResponse { int64 table_definition_id = 1; bool created = 2; } // Defines the input for creating a new table definition. message PostTableDefinitionRequest { // Table name to create inside the target profile. // Must be lowercase, alphanumeric with underscores, // start with a letter, and be <= 63 chars. // Forbidden names include the system columns and tables owned by dedicated // server operations, such as "custom_exchange_rates". The "_id" suffix is // allowed. string table_name = 1; // The table's columns, including its links and stored linked values. // A linked value uses ColumnDefinition.linked_value; its physical type and // money metadata are inferred from the linked source column. repeated ColumnDefinition columns = 3; // Column names to index, matching names declared above. System columns // ("id", "deleted", "created_at", "row_revision") already have indexes, and // a LINK column is indexed when it is created. Requests naming either are // rejected. repeated string indexes = 4; // Name of profile (Postgres schema) where the table will be created. // Same naming rules as table_name; cannot collide with reserved schemas // like "public", "information_schema", or ones starting with "pg_". string profile_name = 5; // Columns whose values identify a row to users in pickers, in the order // they are shown. Each must name one of the user-defined columns above. // Empty means the row is identified by its id alone. repeated string row_display_columns = 7; // ISO-4217 currency the profile keeps its accounting in. A profile is one // accounting entity and keeps one set of books, so this is required only when // the request creates the profile, and is ignored afterwards. It is unrelated // to individual MONEY-column currencies: tables may hold money in any currency, and amounts convert // to this one when they reach the ledger. string accounting_currency = 8; // Initial compiled direct-rate provider. It is enabled for each initial // foreign currency below; more provider/currency bindings may be appended later. string rate_source_id = 11; // Append-only foreign currencies initially enabled for this profile. repeated string foreign_currencies = 12; // When true, the table is stored once in the global physical schema and is // visible from every profile. profile_name and accounting_currency are ignored. bool global = 9; // Names for the columns a definition row generates, in place of the ones the // backend would give them. See GeneratedColumnAlias. repeated GeneratedColumnAlias generated_aliases = 10; } // Renames one column a definition row generates, at the moment it is created. // // A generated column cannot be named in the column list -- the definition row // is required to be named after its own type, and what it expands into is the // backend's to decide. The name is only ever a display name over a physical // column, though, so it is free to be anything: this is where that choice is // made, instead of a SetColumnPresentation call afterwards. // // ACCOUNTING, PHONE and IBAN generated columns may be renamed: their // relationships are recorded by physical column, so the rest of the system can // find them without knowing their display names. ACCOUNTING_TRANSFER connectors // are the exception and are refused here exactly as SetColumnPresentation refuses // them. message GeneratedColumnAlias { // The name the backend would otherwise give the column: one of ACCOUNTING's // "name", "tax_point_date", "debit", "credit" or "account", or a PHONE or // IBAN companion such as "work_phone_ext". Must name a column the request // really generates -- an alias for anything else is rejected rather than // ignored, so a typo cannot pass silently. string generated_name = 1; // What the column should be called instead. Preserved exactly for display. // Aliases may contain Unicode letters, numbers, spaces, punctuation and // symbols, but not leading/trailing whitespace or control characters, and // are limited to 63 UTF-8 bytes. Uniqueness and lookup use a compatibility- // normalized, Unicode-case-folded key that collapses whitespace and ignores // emoji while keeping punctuation significant. string alias = 2; } // Defines the input for explicitly creating tables backed by one invoice // Enables a stored global Typst template for one profile and immediately // creates the input-table family declared by that template. message CreateInvoiceTemplateTableRequest { string profile_name = 1; string template_name = 2; repeated string row_display_columns = 3; } message ApplyInvoiceTemplateTableRequest { string profile_name = 1; string template_name = 2; repeated InvoiceTemplateTableDefinition tables = 3; repeated InvoiceTemplateFieldBinding field_bindings = 4; // The immutable version whose komp_ac_fields the administrator mapped. // Applying never silently switches to a newer version with a different // contract between inspection and submission. int64 template_version_id = 5; } // One administrator-designed table in the template input bundle. The empty // collection_path is the root; a path ending in [] owns that repeated scope. // The nested table definition retains every normal table option, including // ACCOUNTING, generated aliases, ledgers, indexes, links and display columns. message InvoiceTemplateTableDefinition { string collection_path = 1; PostTableDefinitionRequest definition = 2; } enum InvoiceTemplateAccountingRole { INVOICE_TEMPLATE_ACCOUNTING_ROLE_UNSPECIFIED = 0; INVOICE_TEMPLATE_ACCOUNTING_NAME = 1; INVOICE_TEMPLATE_ACCOUNTING_TAX_POINT_DATE = 2; INVOICE_TEMPLATE_ACCOUNTING_ACCOUNT = 3; INVOICE_TEMPLATE_ACCOUNTING_DEBIT = 4; INVOICE_TEMPLATE_ACCOUNTING_CREDIT = 5; } // Maps one path from komp_ac_fields to one table column. A regular binding // names a declared column. An accounting binding names a semantic generated // role, so aliases and the order of Typst fields cannot change its meaning. message InvoiceTemplateFieldBinding { string field_path = 1; string collection_path = 2; string column_name = 3; InvoiceTemplateAccountingRole accounting_role = 4; // Optional source reached through column_name when that column is a LINK. // Both names are empty for a value stored directly on the invoice table. string source_table_name = 5; string source_column_name = 6; } // One physical dynamic table created for an invoice template scope. The root // has an empty collection_path and parent_table_name. Each [] scope names its // collection and the generated table that owns those repeated rows. message GeneratedInvoiceTemplateTable { string table_name = 1; string collection_path = 2; string parent_table_name = 3; string sql = 4; } // Reports the complete table bundle created from one invoice template. message CreateInvoiceTemplateTableResponse { bool success = 1; repeated GeneratedInvoiceTemplateTable tables = 2; int64 template_version_id = 3; } // Defines append-only column additions for an existing table. message AddTableColumnsRequest { // Existing profile/schema name. string profile_name = 1; // Existing table name in the profile. string table_name = 2; // New user-defined columns only. Existing columns cannot be changed here. // Stored linked values use ColumnDefinition.linked_value. repeated ColumnDefinition columns = 3; // Optional indexes for the new columns only. repeated string indexes = 4; // Names for the columns the appended definition rows generate, exactly as on // PostTableDefinitionRequest. repeated GeneratedColumnAlias generated_aliases = 5; } // One atomic structural edit to an existing empty table. // // Removals use stable column IDs rather than aliases. Generated companion // columns must be removed together with their generating column. New columns // follow the same contract as AddTableColumns. message PutTableDefinitionRequest { string profile_name = 1; string table_name = 2; repeated int64 remove_column_ids = 3; repeated ColumnDefinition add_columns = 4; repeated string add_indexes = 5; repeated GeneratedColumnAlias generated_aliases = 6; // Revision returned by GetProfileDetails. Prevents a stale editor from // overwriting a newer structural or presentation change. int64 expected_row_version = 7; // New physical/catalog name. Empty, or equal to table_name, keeps the // current name for backwards-compatible callers. string new_table_name = 8; } message PutTableDefinitionResponse { bool success = 1; string sql = 2; int64 row_version = 3; repeated int64 removed_column_ids = 4; } enum MoneyRounding { MONEY_ROUNDING_NONE = 0; MONEY_ROUNDING_HALF_UP = 1; } // Describes one user-defined column for a table. message ColumnDefinition { // Public display name for this column; the physical column uses a stable // server-assigned ordinal name. Preserved exactly for display. It may contain // Unicode letters, numbers, spaces, punctuation and symbols, but not // leading/trailing whitespace or control characters, and is limited to 63 // UTF-8 bytes. Its canonical form must be unique within the table and cannot // claim a reserved system-column name. string name = 1; // Logical column type. Supported values (case-insensitive): // TEXT // BOOLEAN // INSTANT (local input resolved in the authenticated user's timezone // and displayed in the viewer timezone) // USER_DATETIME (local input resolved in the user's timezone) // RAW_DATETIME (timezone-free civil datetime) // PHONE (international or national phone number; generates extension/type/country/calling-code companions) // TIME (timezone-free time of day) // MONEY (= unconstrained NUMERIC; currency is declared below) // ACCOUNT_STATEMENT_CLASS (A = assets, P = equity and liabilities, // N = expenses, V = revenue) // ACCOUNTING (creates schema-managed name, account, debit, and credit fields; // account always selects a row from the profile's managed ledger_accounts table; // name is limited to 10 characters and one stored row contributes // one line to the profile journal) // ACCOUNTING_TRANSFER (creates automatic source-period/account/book/ // denomination fields and writable target equivalents; one // table may contain only one accounting transfer definition) // INT // BIGINT // DATE // DURATION // PERIOD // LINK(table) → BIGINT referencing that table in the same profile, indexed // automatically. A table may hold several links to the same // target as long as the columns are named differently. string field_type = 2; // MONEY rounding applied before a value is stored. MoneyRounding rounding = 3; // When true, this numeric column is server-owned and projected // from quantity-ledger contributions. bool quantity_ledger = 4; // Canonical uppercase ISO-4217 currency code. Required for MONEY and forbidden // for every other field type. string currency = 5; // When true, the server rejects omitted or explicitly null values. bool required = 6; // Enables a Boolean ledger on Boolean columns. ANY means // one true contribution wins; ALL means one false contribution wins. BooleanLedgerOperator boolean_ledger = 7; // Defines this named column as a stored, read-only value copied through an // existing LINK column. field_type and money metadata are inferred from the // source column and must not be supplied by the caller. optional LinkedValueDefinition linked_value = 8; } message LinkedValueDefinition { // Exact display name of a LINK column in the table being defined. string link_column = 1; // Exact display name of an atomic column in the linked table. string source_column = 2; } enum BooleanLedgerOperator { BOOLEAN_LEDGER_OPERATOR_UNSPECIFIED = 0; BOOLEAN_LEDGER_OPERATOR_ANY = 1; BOOLEAN_LEDGER_OPERATOR_ALL = 2; } // Response after table creation (success + DDL preview). message TableDefinitionResponse { // True if all DB changes and metadata inserts succeeded. bool success = 1; // The actual SQL executed: CREATE TABLE + CREATE INDEX statements. string sql = 2; } // Describes the tree of all profiles and their tables. 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. message Table { // Internal ID from table_definitions.id (metadata record). int64 id = 1; // Table name within the profile (schema). string name = 2; // Links this table declares. One entry per link, so a table that names the // same target twice appears twice. repeated Dependency depends_on = 3; // Columns whose values make up the human-readable row label, in order. repeated string row_display_columns = 4; // "dynamic" for user-defined tables, "system" for backend-managed tables. ManagedTableKind table_kind = 5; // True when this table is shared by every profile. bool global = 6; // Profile (schema) the table is actually stored in. A global table is // listed under every profile it is visible from, so this names the one it // belongs to rather than the one it was reached through, and callers can // use it as the table's identity without deciding anything themselves. string profile_name = 7; } // Profile (schema) entry. message Profile { // Name of the schema/profile (as stored in `schemas.name`). string name = 1; // All tables in that schema and their dependencies. repeated Table tables = 2; } // All profiles in the system. repeated Profile profiles = 1; // The profile holding the tables every profile shares. Callers browse this // one when the user has not chosen a profile, so the name is reported here // rather than being known in advance. string shared_profile_name = 2; } message GetTableCatalogRequest { // Selected profile. Omit this field to request the global-only scope. optional string profile_name = 1; } message GetTableCatalogResponse { repeated ProfileTreeResponse.Table tables = 1; } // Request to fetch all tables, columns and scripts for a profile. message GetProfileDetailsRequest { // Profile (schema) name to fetch details for. string profile_name = 1; } // Response with all tables, columns and scripts for a profile. message GetProfileDetailsResponse { string profile_name = 1; repeated TableDetail tables = 2; } // Request to copy one full profile into a new profile. message CopyProfileRequest { string source_profile_name = 1; string target_profile_name = 2; repeated string table_names = 3; } // Response after copying a profile. message CopyProfileResponse { bool success = 1; string message = 2; int32 tables_copied = 3; int32 scripts_copied = 4; } message ExportProfileBlueprintRequest { string profile_name = 1; // Empty exports every dynamic table in the profile. Otherwise only these tables // are created by import; their unselected local dependencies become requirements. repeated string table_names = 2; } message ExportProfileBlueprintResponse { string blueprint_json = 1; string blueprint_sha256 = 2; int32 tables = 3; int32 required_local_tables = 4; int32 required_global_tables = 5; int32 templates = 6; } message PlanProfileBlueprintImportRequest { string target_profile_name = 1; string blueprint_json = 2; } message ProfileBlueprintImportAction { // One of create, reuse, add, or conflict. string action = 1; string resource = 2; string detail = 3; } message PlanProfileBlueprintImportResponse { bool can_import = 1; string plan_sha256 = 2; repeated ProfileBlueprintImportAction actions = 3; } message ImportProfileBlueprintRequest { string target_profile_name = 1; string blueprint_json = 2; string expected_plan_sha256 = 3; } message ImportProfileBlueprintResponse { bool success = 1; string message = 2; int32 tables_created = 3; int32 globals_created = 4; int32 globals_reused = 5; int32 templates_created = 6; int32 templates_reused = 7; } enum AliasChangeKind { ALIAS_CHANGE_KIND_UNSPECIFIED = 0; ALIAS_CHANGE_KIND_COLUMN = 1; ALIAS_CHANGE_KIND_OPTION = 2; } message GetAliasChangeHistoryRequest { string profile_name = 1; optional int64 table_definition_id = 2; optional int64 column_id = 3; AliasChangeKind alias_kind = 4; optional string option_value = 5; uint32 limit = 6; } message AliasChangeHistoryEntry { int64 id = 1; string change_set_id = 2; AliasChangeKind alias_kind = 3; string profile_name = 4; int64 table_definition_id = 5; string table_name = 6; optional int64 column_id = 7; string column_name = 8; optional string option_value = 9; optional string old_alias = 10; optional string new_alias = 11; optional string changed_by_user_id = 12; optional string changed_by_user_name = 13; string changed_at = 14; } message GetAliasChangeHistoryResponse { string profile_name = 1; repeated AliasChangeHistoryEntry entries = 2; } enum ManagedTableKind { MANAGED_TABLE_KIND_UNSPECIFIED = 0; MANAGED_TABLE_KIND_DYNAMIC = 1; MANAGED_TABLE_KIND_SYSTEM = 2; } // Describes a table with its columns and associated scripts. message TableDetail { string name = 1; int64 id = 2; repeated ColumnDefinition columns = 3; repeated ScriptInfo scripts = 4; repeated string row_display_columns = 6; map column_behaviors = 7; ManagedTableKind table_kind = 8; bool global = 9; // Revision of this table definition for optimistic concurrency control. int64 row_version = 10; // Profile (schema) the table is actually stored in, which is not the // requested profile when a global table is being listed. See // ProfileTreeResponse.Table.profile_name. string profile_name = 11; // True when the physical table contains at least one row, including a // soft-deleted row. Populated tables are append-only: PutTableDefinition is // no longer available, while AddTableColumns remains available. bool has_data = 12; // User-managed single-column indexes. Backend-managed indexes are omitted. repeated string indexes = 13; } // Server-owned behavior for one logical column returned in table details. message ColumnBehavior { // True when the server created the column as a companion of another column. bool generated = 1; // True when clients must display but never submit edits for the column. bool read_only = 2; // Logical source column name, empty for ordinary user-defined columns. string generated_from = 3; // True when clients may offer this column in an alias rename picker. bool renameable = 4; // Stable public identity used when updating this column's presentation. int64 column_id = 5; // True when bundled data-entry clients should not render this column. // This is not an authorization boundary; data APIs still expose the column. bool hidden_from_forms = 6; // Current public option names. For a renamed option, both fields contain its // alias; the stored value is never disclosed. Public writes use the alias. repeated OptionValueAlias option_value_aliases = 7; } // A script that targets a specific column in a table. message ScriptInfo { int64 script_id = 1; string target_column = 2; string target_column_type = 3; string script = 4; string description = 5; } // One column's desired public presentation. Its position in the containing // repeated field is its presentation order. message ColumnPresentation { // Stable public identity of the table_definition_columns row. int64 column_id = 1; string alias = 2; } // Atomically replaces every user-visible column alias and their order. message SetColumnPresentationRequest { string profile_name = 1; string table_name = 2; repeated ColumnPresentation columns = 3; // Row version returned by GetProfileDetails when this presentation was read. int64 expected_row_version = 4; } message SetColumnPresentationResponse { bool success = 1; string message = 2; repeated ColumnPresentation columns = 3; // New row version after the update. int64 row_version = 4; } // Atomically replaces the columns whose values identify rows in pickers and // link labels. Their order is the order in which their values are displayed. message SetRowDisplayColumnsRequest { string profile_name = 1; string table_name = 2; repeated string row_display_columns = 3; // Row version returned by GetProfileDetails when this metadata was read. int64 expected_row_version = 4; } message SetRowDisplayColumnsResponse { bool success = 1; repeated string row_display_columns = 2; // New row version after the update, or the current version for a no-op. int64 row_version = 3; } // Atomically replaces the table's user-managed single-column indexes. Indexes // owned by the backend, including link and navigation indexes, are unchanged. message SetTableIndexesRequest { string profile_name = 1; string table_name = 2; repeated string indexes = 3; // Row version returned by GetProfileDetails when the indexes were read. int64 expected_row_version = 4; } message SetTableIndexesResponse { bool success = 1; repeated string indexes = 2; // New row version after the update, or the current version for a no-op. int64 row_version = 3; } message SetColumnRequiredRequest { string profile_name = 1; string table_name = 2; // Stable column identity returned in GetProfileDetails.column_behaviors. int64 column_id = 3; bool required = 4; // Row version returned by GetProfileDetails when the column was read. int64 expected_row_version = 5; } message SetColumnRequiredResponse { bool success = 1; int64 column_id = 2; bool required = 3; // New row version after the update, or the current version for a no-op. int64 row_version = 4; } // One public option name. `value` identifies the option by its current public // alias and `alias` is its desired public alias; stored values remain internal. message OptionValueAlias { string value = 1; string alias = 2; } message SetColumnOptionAliasesRequest { string profile_name = 1; string table_name = 2; int64 column_id = 3; // Partial sets are supported; omitted values use their canonical spelling. // An empty list removes every alias from the column. repeated OptionValueAlias aliases = 4; int64 expected_row_version = 5; } message SetColumnOptionAliasesResponse { bool success = 1; string message = 2; int64 column_id = 3; repeated OptionValueAlias aliases = 4; int64 row_version = 5; } message SetColumnFormVisibilityRequest { string profile_name = 1; string table_name = 2; int64 column_id = 3; bool hidden_from_forms = 4; // Row version returned by GetProfileDetails when the column was read. int64 expected_row_version = 5; } message SetColumnFormVisibilityResponse { bool success = 1; string message = 2; int64 column_id = 3; bool hidden_from_forms = 4; // New row version after the update. int64 row_version = 5; } // Request to delete one table definition entirely. message DeleteTableRequest { // Profile (schema) name owning the table (must exist). string profile_name = 1; // Table to drop (must exist in the profile). // Executes DROP TABLE "profile"."table" CASCADE and then removes metadata. string table_name = 2; } // Response after table deletion. message DeleteTableResponse { // True if table and metadata were successfully deleted in one transaction. bool success = 1; // Human-readable summary of what was removed. string message = 2; } message DeleteProfileRequest { string profile_name = 1; } message DeleteProfileResponse { bool success = 1; string message = 2; int32 tables_deleted = 3; } // How a column type is spelled in ColumnDefinition.field_type. enum ColumnTypeSpelling { // The name is the whole spelling: "text", "money", "gtin_13". COLUMN_TYPE_SPELLING_BARE = 0; reserved 1; // The name takes the name of another table in the same profile: // "link(adresar)". The column holds that table's id, and the server creates // the foreign key and its index. A picker offers the profile's other tables // as the argument. COLUMN_TYPE_SPELLING_LINK = 2; } // Response describing the whole column-type vocabulary. // // This is the authority a client builds its column-type picker from: every rule // a client would otherwise hardcode about what a type means is a field here. The // list covers types clients may NOT declare as well (see `declarable`), so that // the same call also explains the types GetProfileDetails reports back for // server-generated companion columns. message ListColumnTypesResponse { // One column type and everything a client needs to know to offer it. message ColumnType { // Logical column type (e.g. "money", "instant"). Passed to the server as // ColumnDefinition.field_type — see `spelling`, which is what says whether // this name is the whole spelling. string name = 1; // Underlying PostgreSQL type the logical type maps to (e.g. "NUMERIC"). // Empty when `compound` is true. string sql_type = 2; // False for types the server generates on its own and rejects when a client // declares them: the phone and IBAN companions, and the accounting-transfer // connectors. A column-type picker must offer only declarable types. bool declarable = 3; // True when the type is a definition row rather than a column: it expands // into several schema-managed companion columns and no column of this name // survives. A compound type can therefore never be indexed, never be a row // display column, and has no single sql_type of its own. bool compound = 4; // Whether `name` is the whole spelling or takes arguments. ColumnTypeSpelling spelling = 5; // Whether ColumnDefinition.currency is required. Currency is rejected on // every type where this is false. bool requires_currency = 6; // True when the type may only be chosen while the table is being created. // AddTableColumns rejects these, because they bring schema-managed columns // that cannot be bolted onto a table that already exists. bool creation_only = 7; // Whether ColumnDefinition.quantity_ledger may be set on this type. bool allows_quantity_ledger = 8; // Whether ColumnDefinition.boolean_ledger may be set on this type. bool allows_boolean_ledger = 11; // Optional name grouping several types a client offers behind one choice — // "temporal" for the date and time types, "gtin" for the GTIN lengths. // Empty when the type stands on its own. string group = 9; // One column a compound type expands into. message GeneratedColumn { // Name the server gives the column. Fixed, and reserved: a table // declaring a compound type may not also declare a column of this name. string name = 1; // The generated column's own logical type, as this same catalog // describes it. string field_type = 2; // Whether the generated column carries the currency and rounding // declared on the definition row. bool inherits_currency = 3; } // What this type expands into, in the order the server creates the // columns. Populated for compound types only, where the generated names // are fixed; empty for every other type, including the ones whose // companions are named after the declared column (phone, iban). // // A picker offering a compound type shows these, so choosing it is not a // blind choice. The columns stay the server's to create — none of them may // be declared. repeated GeneratedColumn generated_columns = 10; } // Every column type, declarable or not, ordered by name. repeated ColumnType column_types = 1; // Every canonical ISO-4217 code accepted by currency-bearing columns and // profile accounting settings, ordered alphabetically. repeated string currency_codes = 2; }