/**
 * Copyright (c) 2020-present, Goldman Sachs
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { Column, type Database, type Join, type Milestoning, type Schema, type Table, View } from '@finos/legend-graph';
/**
 * Tables and Views are the two top-level "relations" a Database schema can
 * contain. They share a common metamodel ancestor (NamedRelation) and almost
 * the same on-canvas treatment, so most helpers and the React node component
 * accept either.
 */
export type DatabaseRelation = Table | View;
export declare const isView: (relation: DatabaseRelation) => relation is View;
/**
 * Stable identifier for a relation within a Database, encoded as
 * `<schema>.<name>`. Schema-qualified to disambiguate same-named relations
 * across schemas. Works for both Tables and Views.
 */
export declare const getRelationId: (relation: DatabaseRelation) => string;
/**
 * Display string for a relational data type (e.g. `VARCHAR(40)`,
 * `DECIMAL(10,4)`). Wraps the upstream helper so the editor doesn't need to
 * know about RelationalDataType subclasses directly.
 */
export declare const getColumnTypeLabel: (column: Column) => string;
/**
 * `Relation.columns` is statically typed as `RelationalOperationElement[]`
 * (the broader supertype) but is populated with `Column` instances at runtime
 * for tables. Filter so the form-mode editor can rely on the narrower type
 * without casting at every call site.
 */
export declare const getTableColumns: (table: Table) => Column[];
/**
 * Whether a column participates in a relation's primary key. Both Tables and
 * Views can declare a primary key (`primaryKey: Column[]`). For Views we
 * compare by name because a view's `columnMappings` carry their column name
 * directly rather than referencing the same `Column` instances.
 */
export declare const isPrimaryKey: (relation: DatabaseRelation, columnName: string) => boolean;
/**
 * Placeholder text shown while view-column Pure-code formulas are still
 * loading (or if rendering them failed). Centralized so both the canvas
 * table node and the tree column row stay in sync.
 */
export declare const VIEW_COLUMN_FORMULA_PLACEHOLDER = "calculate [...]";
/**
 * Resolve the Pure-code formula for a single view column mapping. Looks the
 * pre-rendered formula up by `<schema>.<view>.<column>` key in the map
 * populated by `DatabaseEditorState.loadViewColumnFormulas()`. Falls back to
 * a static placeholder when the formula isn't ready yet (initial load,
 * background re-render) or the engine couldn't render it.
 *
 * The map is passed in (not read directly here) so this module stays
 * framework-agnostic — DatabaseDiagramHelper has no MobX dependency.
 */
export declare const resolveViewColumnFormula: (formulas: ReadonlyMap<string, string>, schemaName: string, viewName: string, columnName: string) => string;
/**
 * Placeholder text shown while filter Pure-code formulas are still loading
 * (or if rendering them failed). Centralized so the side-panel filter row
 * has a sensible fallback during the brief async window.
 */
export declare const FILTER_FORMULA_PLACEHOLDER = "filter [...]";
/**
 * Resolve the Pure-code formula for a single database-level filter. Filter
 * names are unique within a Database, so the lookup key is just the filter
 * name (no schema qualifier needed). Falls back to a static placeholder when
 * the formula isn't ready yet or the engine couldn't render it.
 */
export declare const resolveFilterFormula: (formulas: ReadonlyMap<string, string>, filterName: string) => string;
/**
 * Placeholder shown while a join's Pure-code operation is loading or if
 * rendering failed. Same async-load pattern as filters and view-column
 * formulas — reused so the side panel and canvas tooltips stay in sync.
 */
export declare const JOIN_FORMULA_PLACEHOLDER = "join [...]";
export declare const resolveJoinFormula: (formulas: ReadonlyMap<string, string>, joinName: string) => string;
/**
 * Placeholder shown for view groupBy expressions while the engine render
 * is in flight or if rendering failed. Kept distinct from the column-mapping
 * placeholder so users can tell at a glance which kind of expression is
 * still loading.
 */
export declare const VIEW_GROUP_BY_FORMULA_PLACEHOLDER = "group by [...]";
/**
 * Resolve the Pure-code formula for a single view groupBy column expression.
 * Keys mirror the loader in `DatabaseEditorState`:
 * `<schema>.<view>.groupBy[<index>]`. Falls back to the static placeholder
 * when the formula isn't ready yet.
 */
export declare const resolveViewGroupByFormula: (formulas: ReadonlyMap<string, string>, schemaName: string, viewName: string, index: number) => string;
/**
 * Lowercase, trimmed search-text matcher used by the side-panel tree.
 * Empty query matches everything (so consumers don't need a special case).
 * Match is case-insensitive substring \u2014 not fuzzy \u2014 because users
 * typically know the exact prefix of the schema/relation/column they're
 * looking for and substring keeps the "what matched" obvious.
 */
export declare const matchesSearch: (name: string, query: string) => boolean;
/**
 * Renders a single `Milestoning` instance into a short, grammar-flavored
 * label and a longer human description. Mirrors the four concrete subclasses
 * the metamodel ships today:
 *
 *   - `BusinessMilestoning`         — `business[from..thru]` ("thru inclusive" tag)
 *   - `BusinessSnapshotMilestoning` — `business snapshot(<col>)`
 *   - `ProcessingMilestoning`       — `processing[in..out]` ("out inclusive" tag)
 *   - `ProcessingSnapshotMilestoning` — `processing snapshot(<col>)`
 *
 * Unknown subclasses (extension milestonings introduced via plugins) fall
 * back to the constructor name so the user at least sees "something is
 * configured here" instead of a silent omission.
 */
export interface MilestoningSummary {
    /** Short grammar-style label, e.g. `business[from..thru]`. */
    label: string;
    /** Longer human-readable description used as the tooltip. */
    description: string;
    /** Stable kind tag for styling: `business` | `processing` | `unknown`. */
    kind: 'business' | 'processing' | 'unknown';
}
export declare const summarizeMilestoning: (milestoning: Milestoning) => MilestoningSummary;
/**
 * Whether a join's two endpoints are the same relation (e.g. a hierarchy
 * self-join: `Employee → Employee` on `managerId = id`). We treat any join
 * whose first alias pair has identical source/target relation ids as a
 * self-join — mirrors how `buildJoinEdges` matches endpoints.
 */
export declare const isSelfJoin: (join: Join) => boolean;
/**
 * Whether either endpoint of a join lives outside `database` (i.e. resolves
 * to a relation owned by another, included, store). Used to surface a
 * "CROSS-DB" badge in the side panel and to render the canvas placeholder
 * node for the foreign endpoint.
 */
export declare const isCrossDatabaseJoin: (join: Join, database: Database) => boolean;
/**
 * Number of column rows a relation's table-node will render. Tables expose
 * Column[] via `columns`, Views expose ColumnMapping[] via `columnMappings`.
 */
export declare const getRelationColumnCount: (relation: DatabaseRelation) => number;
/**
 * Identify columns that participate in any join in the database. Used to badge
 * columns as foreign keys in the table node.
 *
 * Note: in Pure relational, joins ARE the relationships — there is no separate
 * FK constraint on the column. A column is "FK-like" iff some join's operation
 * references it.
 */
export declare const collectForeignKeyColumns: (database: Database) => Set<Column>;
export interface DatabaseDiagramJoinEdge {
    /** Stable id used by React Flow. */
    id: string;
    /** Join name (used as edge label). */
    name: string;
    /** Source relation id (`<schema>.<name>`). */
    source: string;
    /** Target relation id (`<schema>.<name>`). */
    target: string;
    /** Original `Join` reference for identity-based selection matching. */
    join: Join;
    /** True when both endpoints are the same relation (self-join). React Flow
     *  renders these as loop edges; we use this flag so the canvas can pick a
     *  distinct edge type / styling without re-walking aliases. */
    isSelfJoin: boolean;
    /** True when at least one endpoint is *not* in this database. The missing
     *  endpoint is rendered as a stub placeholder node instead of a real
     *  table-node so users can still see the relationship at a glance. */
    isCrossDatabase: boolean;
}
/** Synthetic relation id used for the placeholder node that stands in for a
 *  cross-database join's foreign endpoint. Includes the schema-qualified
 *  source path so the same foreign relation is reused across multiple joins
 *  rather than producing one stub per join. */
export declare const getForeignRelationStubId: (ownerPath: string, schemaName: string, relationName: string) => string;
export interface ForeignRelationStub {
    id: string;
    schemaName: string;
    relationName: string;
    ownerPath: string;
}
export interface DatabaseDiagramBuildResult {
    edges: DatabaseDiagramJoinEdge[];
    /** Foreign endpoints that need a placeholder node on the canvas. Empty
     *  when there are no cross-database joins. Deduplicated by stub id. */
    foreignStubs: ForeignRelationStub[];
}
/**
 * Walk all joins in the database and produce a deduplicated list of edges
 * between relations (tables and/or views), including self-joins (rendered
 * as loop edges) and cross-database joins (whose foreign endpoint becomes
 * a placeholder stub).
 *
 * Implementation notes:
 * - `Join.aliases` typically contains both directions `(A→B)` and `(B→A)` as a
 *   lookup optimization. We treat A↔B as a single edge and use the first alias.
 * - Self-joins (A↔A) are kept and flagged via `isSelfJoin` so the canvas can
 *   render a loop edge instead of skipping them.
 * - Joins whose endpoints reference relations outside this database (typically
 *   through `includes` / `includedStoreSpecifications`) are kept and flagged
 *   via `isCrossDatabase`. The foreign endpoint is replaced with a stub id so
 *   the caller can render a small placeholder node beside the in-DB endpoint.
 */
export declare const buildJoinEdges: (database: Database) => DatabaseDiagramBuildResult;
export interface LaidOutNode {
    id: string;
    x: number;
    y: number;
}
export interface DatabaseDiagramRelationNode {
    id: string;
    relation: DatabaseRelation;
    /** Estimated height in pixels — driven by column count for dagre layout. */
    estimatedHeight: number;
}
export declare const estimateNodeHeight: (relation: DatabaseRelation) => number;
/**
 * Run dagre on the relation/edge graph and return positions keyed by
 * relation id. Uses left-to-right layering, which suits ERDs better than
 * top-down.
 */
export declare const layoutDatabaseDiagram: (nodes: DatabaseDiagramRelationNode[], edges: DatabaseDiagramJoinEdge[]) => Map<string, LaidOutNode>;
/**
 * Flat list of (schema, relation) pairs in deterministic order — used by the
 * canvas builder. Tables come before views within each schema (alphabetic
 * within each kind), so the canvas layout stays stable as a database grows.
 */
export declare const getOrderedRelations: (database: Database) => {
    schema: Schema;
    relation: DatabaseRelation;
}[];
//# sourceMappingURL=DatabaseDiagramHelper.d.ts.map