from lumaCLI.metadata.sources.powerbi.models import (
    DataflowDetails,
    WorkspaceInfo,
)
from lumaCLI.metadata.sources.powerbi.transform import (
    _extract_dataflow_table_from_expression,
    _extract_entity_block,
    _extract_model_from_dataflow_entity_block,
    _extract_table_from_expression,
    extract_tables,
)


def test__extract_table_from_expression():
    expr = 'let\n    Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com","somedb"),\n    sandbox = Source{[Name="finance"]}[Data],\n    kpi_p1 = sandbox{[Name="fi_kpi_p1_table"]}[Data]\nin\n    kpi_p1'
    expected = {
        "name": "fi_kpi_p1_table",
        "schema": "finance",
        "database": "somedb",
        "tags": [{"source_system": "AmazonRedshift:Direct"}],
    }
    assert _extract_table_from_expression(expr) == expected

    expr2 = 'let\n    Source_Redshift = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com","somedb"),\n    finance = Source_Redshift{[Name="finance"]}[Data],\n    fi_zsd_familt = finance{[Name="fi_zsd_familt"]}[Data],\n    #"Renamed Columns" = Table.RenameColumns(fi_zsd_familt,{{"sub_family_code", "Family Code"}, {"sub_family_desc", "Family"}})\nin\n    #"Renamed Columns"'
    expected2 = {
        "name": "fi_zsd_familt",
        "schema": "finance",
        "database": "somedb",
        "tags": [{"source_system": "AmazonRedshift:Direct"}],
    }
    assert _extract_table_from_expression(expr2) == expected2

    expr3 = 'let\n    Source_Redshift = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com","somedb"),\n    finance = Source_Redshift{[Name="finance"]}[Data],\n    fi_tcurr = finance{[Name="fi_tcurr"]}[Data],\n    #"Renamed Columns2" = Table.RenameColumns(fi_tcurr,{{"exch_rate_type", "Exch Rate Type"}, {"from_currency", "From Currency"}, {"to_currency", "To Currency"}, {"valid_from", "Valid From"}, {"ratio_from", "Ratio From"}, {"exchange_rate", "Exchange Rate"}, {"ratio_to", "Ratio To"}}),\n    #"Changed Type Valid From" = Table.TransformColumnTypes(#"Renamed Columns2", {{"Valid From", type date}}, "es-ES"),\n    \n    #"Filtered BUDG & M" = Table.SelectRows(#"Changed Type Valid From", each ([Exch Rate Type] = "BUDG" or [Exch Rate Type] = "M") ),\n    #"Filtered From Curr EUR" = Table.SelectRows(#"Filtered BUDG & M", each ([From Currency] = "EUR") ),\n    #"Add Year" = Table.AddColumn(#"Filtered From Curr EUR", "Year", each Date.Year([Valid From])),\n    #"Add Month" = Table.AddColumn(#"Add Year", "Month", each Date.Month([Valid From])),\n    #"Add Day" = Table.AddColumn(#"Add Month", "Day", each Date.Day([Valid From])),\n    #"Changed Data Types" = Table.TransformColumnTypes(#"Add Day",{{"Year", Int64.Type}, {"Month", Int64.Type}, {"Day", Int64.Type}}),\n    #"Filtered Day 1" = Table.SelectRows(#"Changed Data Types", each ([Day] = 1) ),\n    #"Renamed Columns" = Table.RenameColumns(#"Filtered Day 1",{{"Valid From", "EX Date"}}),\n    #"Filtered Rows" = Table.SelectRows(#"Renamed Columns", each [Year] >= 2022)\nin\n    #"Filtered Rows"'
    expected3 = {
        "name": "fi_tcurr",
        "schema": "finance",
        "database": "somedb",
        "tags": [{"source_system": "AmazonRedshift:Direct"}],
    }
    assert _extract_table_from_expression(expr3) == expected3

    # NativeQuery example - we don't extract models from those, as they're unstructured.
    expr4 = "let\n    Source_Redshift = Value.NativeQuery(AmazonRedshift.Database(\"redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com\",\"somedb\"), \"SELECT #(lf)  LOWER(p.model) AS model,#(lf)  s.product_line,#(lf)  s.product_line_detail,#(lf)  SUM(COALESCE(s.placements, 0)) AS total_placements#(lf)FROM finance.fi_part_numbers_for_placements p#(lf)LEFT JOIN (#(lf)  SELECT#(lf)    material,#(lf)    product_line,#(lf)    product_line_detail,#(lf)    COALESCE(SUM(sales_qty), 0) + COALESCE(SUM(actual_qty_reagent_rental), 0) AS placements#(lf)  FROM finance.fi_zsd_sald#(lf)  WHERE fiscal_year BETWEEN EXTRACT(YEAR FROM CURRENT_DATE) - 2 #(lf)                         AND EXTRACT(YEAR FROM CURRENT_DATE) + 1#(lf)    AND sales_org IN (#(lf)      '001', '005', '006', '015', #(lf)      '133', '134', '135', #(lf)      '1693', '175', '176', #(lf)      '193', '1933'#(lf)    )#(lf)  GROUP BY material, product_line, product_line_detail#(lf)) s ON p.material = s.material#(lf)GROUP BY LOWER(p.model), s.product_line, s.product_line_detail#(lf)HAVING SUM(COALESCE(s.placements, 0)) <> 0\", null, [EnableFolding=true])\nin\n    Source_Redshift"
    assert _extract_table_from_expression(expr4) is None


def test__extract_entity_block():
    document = """
section Section1;
shared MyEntity = let
  Source = AmazonRedshift.Database("host", "db", []),
  #"Navigatiion 1" = Source{[Name = "my_schema"]}[Data],
  #"Navi 2" = #"Navigacion 1"{[Name = "my_table"]}[Data]
in
  #"Navigation 2";
shared OtherEntity = let
  Source = AmazonRedshift.Database("host", "db", []),
  #"Nav 1" = Source{[Name = "other"]}[Data],
  #"Nav 2" = #"Navigation 1"{[Name = "othertable"]}[Data]
in
  #"Nav 2";
"""
    block = _extract_entity_block("MyEntity", document)
    assert block is not None
    assert "Source = AmazonRedshift.Database" in block
    assert "my_schema" in block
    assert "my_table" in block


def test__extract_entity_block_complex():
    document = """
section Section1;
shared #"02_Activities" = let
  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),
  #"Navigation 1" = Source{[Name = "compliance"]}[Data],
  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_activities_master"]}[Data],
  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"id_evento", "ID Evento"}, {"id_actividad", "ID Actividad"}, {"actividad_descripcion", "Actividad descripción"}, {"tipo_de_actividad", "Tipe de actividad"}, {"inicio_de_validez", "Inicio de validez"}, {"fin_de_validez", "Fin de validez"}, {"hora_inicio_actividad", "Hora inicio actividad"}, {"hora_fin_actividad", "Hora fin actividad"}, {"creado_por", "Creado por"}, {"creado_el", "Creado el"}, {"hora", "Hora"}, {"modificado_por", "Modificado por"}, {"modificado_el", "Modificado el"}, {"hora_modificacion", "Hora modificación"}})
in
  #"Renamed columns";
shared #"BU&Geographies" = let
  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),
  #"Navigation 1" = Source{[Name = "compliance"]}[Data],
  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_bu_geographies"]}[Data],
  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"sociedad", "Sociedad"}, {"code", "Code"}, {"name", "Name"}, {"grupo", "Grupo"}, {"bu", "BU"}, {"geography", "Geography"}})
in
  #"Renamed columns";
shared #"09_T&E" = let
  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),
  #"Navigation 1" = Source{[Name = "compliance"]}[Data],
  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_concur_te"]}[Data],
  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"employee_id", "Employee ID"}, {"employee_and_id", "Employee + ID"}, {"no_times", "Nº Times"}, {"report_name", "Report Name"}, {"submit_date", "Submit Date"}, {"total_approved_amount_rpt", "Total Approved Amount (rpt)"}, {"transaction_date", "Transaction Date"}, {"expense_type", "Expense Type"}, {"vendor", "Vendor"}, {"purpose", "Purpose"}, {"payment_type", "Payment Type"}, {"approved_amount_rpt", "Approved Amount (rpt)"}, {"attendee", "Attendee"}, {"title", "Title"}, {"company", "Company"}, {"type", "Type"}, {"amount", "Amount"}}),
  Custom = Table.TransformColumnTypes(Table.AddColumn(#"Renamed columns", "ZESE", each Text.Start([Employee ID], 3)), {{"ZESE", type text}})
in
  Custom;
shared #"08_Cuentas" = let
  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),
  #"Navigation 1" = Source{[Name = "compliance"]}[Data],
  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_cuentas_master"]}[Data],
  Custom = Table.RenameColumns(#"Navigation 2", {{"cuentas", "Cuentas"}, {"descripcion", "Descripción"}})
in
  Custom;
shared #"05_Event Type" = let
  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),
  #"Navigation 1" = Source{[Name = "compliance"]}[Data],
  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_event_type"]}[Data],
  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"event_type", "Event type"}, {"description", "Description"}})
in
  #"Renamed columns";
shared #"Ingreso/Gasto" = let
  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),
  #"Navigation 1" = Source{[Name = "compliance"]}[Data],
  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_grupos_master"]}[Data],
  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"cuenta", "Cuenta"}, {"grupo", "Grupo"}})
in
  #"Renamed columns";
shared Mapping = let
  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),
  #"Navigation 1" = Source{[Name = "compliance"]}[Data],
  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_hcp_partner_mapping"]}[Data],
  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"hcp_partner_id", "HCP Partner ID"}, {"main_customer", "Main Customer"}})
in
  #"Renamed columns";
shared #"InGr Mapping" = let
  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),
  #"Navigation 1" = Source{[Name = "compliance"]}[Data],
  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_industry_group_mapping"]}[Data],
  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"ing", "InG"}, {"industry_group", "Industry Group"}, {"classification", "Classification"}})
in
  #"Renamed columns";
shared #"Industry Group" = let
  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),
  #"Navigation 1" = Source{[Name = "compliance"]}[Data],
  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_industry_group_sales"]}[Data],
  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"year", "Year"}, {"code", "Code"}, {"sales_organization", "Sales Organization"}, {"ing", "InG"}, {"industry_group", "Industry Group"}, {"sales", "Sales"}})
in
  #"Renamed columns";
shared #"06_Interaction Type" = let
  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),
  #"Navigation 1" = Source{[Name = "compliance"]}[Data],
  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_interaction_type"]}[Data],
  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"interaction_type", "Interaction Type"}, {"language", "Language"}, {"name", "Name"}})
in
  #"Renamed columns";
shared #"03_Interactions" = let
  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),
  #"Navigation 1" = Source{[Name = "compliance"]}[Data],
  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_interactions_master"]}[Data],
  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"id_evento", "ID Evento"}, {"id_actividad", "ID Actividad"}, {"id_nteraccion", "ID Interacción"}, {"hcp_partner_id", "HCP Partner ID"}, {"tipo_de_hcp_partner", "Tipo de HCP partner"}, {"prestacion_de_servicio", "Prestación de servicio"}, {"tipo_de_interaccion", "Tipo de interacción"}, {"hco_employer_id", "HCO Employer ID"}, {"creado_por", "Creado por"}, {"creado_el", "Creado el"}, {"hora", "Hora"}, {"modificado_por", "Modificado por"}, {"modificado_el", "Modificado el"}, {"hora_modificacion", "Hora modificación"}})
in
  #"Renamed columns";
shared #"10_Tabla ZESE" = let
  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),
  #"Navigation 1" = Source{[Name = "compliance"]}[Data],
  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_zeses"]}[Data],
  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"zese", "ZESE"}, {"mycompany_company", "MycompanyCompany"}, {"code", "Code"}, {"sociedad", "Sociedad"}})
in
  #"Renamed columns";
shared #"01_Events" = let
  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),
  #"Navigation 1" = Source{[Name = "compliance"]}[Data],
  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_events_master"]}[Data],
  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"id_evento", "ID Evento"}, {"evento_descripcion", "Evento descripción"}, {"organizacion_ventas", "Organización ventas"}, {"inicio_de_validez", "Inicio de validez"}, {"fin_de_validez", "Fin de validez"}, {"tipo_de_evento", "Tipo de evento"}, {"proyecto", "Proyecto"}, {"modificado_el", "Modificado el"}, {"modificado_por", "Modificado por"}, {"hora", "Hora"}, {"creado_el", "Creado el"}, {"creado_por", "Creado por"}, {"numero_invitados", "Número invitados"}, {"numero_de_staff", "Número de staff"}, {"clave_de_pais", "Clave de país"}, {"poblacion", "Población"}, {"grouping_code", "Grouping Code"}, {"grupo_division", "Grupo División"}, {"division", "División"}})
in
  #"Renamed columns";
shared #"04_Expenses" = let
  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),
  #"Navigation 1" = Source{[Name = "compliance"]}[Data],
  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_expenses_master"]}[Data],
  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"id_evento", "ID Evento"}, {"id_actividad", "ID Actividad"}, {"id_interaccion", "ID Interacción"}, {"posicion_gastos", "Posición gastos"}, {"hcp_partner_id", "HCP Partner ID"}, {"tipo_de_hcp_partner", "Tipo de HCP partner"}, {"transparencia", "Transparencia"}, {"concepto_de_gasto", "Concepto de gasto"}, {"acreedor", "Acreedor"}, {"fecha_factura", "Fecha factura"}, {"base_p_plazo_pago", "Base p.plazo pago"}, {"valor_neto", "Valor neto"}, {"moneda", "Moneda"}, {"impte_impto_mon_loc", "Impte.impto.mon.loc."}, {"percentaje", "Porcentaje"}, {"cuenta_de_mayor", "Cuenta de mayor"}, {"centro_de_coste", "Centro de coste"}, {"ejercicio", "Ejercicio"}, {"no_documento", "Nº documento"}, {"creado_por", "Creado por"}, {"creado_el", "Creado el"}, {"hora", "Hora"}, {"modificado_por", "Modificado por"}, {"modificado_el", "Modificado el"}, {"hora_modificacion", "Hora modificación"}, {"exchange_rate", "Currency Rates.Exchange rate"}})
in
  #"Renamed columns";
shared companies = let
  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),
  #"Navigation 1" = Source{[Name = "compliance"]}[Data],
  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_sales_companies"]}[Data],
  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"sales_organization", "Sales Organization"}, {"sociedad", "Sociedad"}, {"code", "Code"}})
in
  #"Renamed columns";
shared mastercalendar = let
    StartDate = #date(2016,1,1),
    EndDate = #date(2025,12,31),
    NumberOfDays = Duration.Days( EndDate - StartDate ),
    Dates = List.Dates(StartDate, NumberOfDays+1, #duration(1,0,0,0)),
    #"Converted to Table" = Table.FromList(Dates, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    #"Renamed Columns" = Table.RenameColumns(#"Converted to Table",{{"Column1", "FullDateAlternateKey"}}),
    #"Changed Type" = Table.TransformColumnTypes(#"Renamed Columns",{{"FullDateAlternateKey", type date}}),
    #"Inserted Year" = Table.AddColumn(#"Changed Type", "Año", each Date.Year([FullDateAlternateKey]), type number),
    #"Inserted Month" = Table.AddColumn(#"Inserted Year", "Mes Num", each Date.Month([FullDateAlternateKey]), type number),
    #"Inserted Month Name" = Table.AddColumn(#"Inserted Month", "Mes", each Date.MonthName([FullDateAlternateKey]), type text),
    #"Inserted Quarter" = Table.AddColumn(#"Inserted Month Name", "Trimestre", each Date.QuarterOfYear([FullDateAlternateKey]), type number),
    #"Inserted Week of Year" = Table.AddColumn(#"Inserted Quarter", "Semana del año", each Date.WeekOfYear([FullDateAlternateKey]), type number),
    #"Inserted Week of Month" = Table.AddColumn(#"Inserted Week of Year", "Semana del mes", each Date.WeekOfMonth([FullDateAlternateKey]), type number),
    #"Inserted Day" = Table.AddColumn(#"Inserted Week of Month", "Dia Num", each Date.Day([FullDateAlternateKey]), type number),
    #"Inserted Day of Week" = Table.AddColumn(#"Inserted Day", "Dia de la semana", each Date.DayOfWeek([FullDateAlternateKey]), type number),
    #"Inserted Day of Year" = Table.AddColumn(#"Inserted Day of Week", "Dia del año", each Date.DayOfYear([FullDateAlternateKey]), type number),
    #"Inserted Day Name" = Table.AddColumn(#"Inserted Day of Year", "Dia", each Date.DayOfWeekName([FullDateAlternateKey]), type text),
    #"Columnas con nombre cambiado" = Table.RenameColumns(#"Inserted Day Name",{{"FullDateAlternateKey", "Fecha"}})
in
    #"Columnas con nombre cambiado";
shared #"07_Contabilidad" = let
  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),
  #"Navigation 1" = Source{[Name = "compliance"]}[Data],
  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_contabilidad"]}[Data],
  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"cuenta", "Cuenta"}, {"asignacion", "Asignación"}, {"fe_contabilizacion", "Fe.contabilización"}, {"importe_en_moneda_local", "Importe en moneda local"}, {"texto", "Texto"}, {"sociedad", "Sociedad"}})
in
  #"Renamed columns";
shared #"Open Opp" = let
  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),
  #"Navigation 1" = Source{[Name = "compliance"]}[Data],
  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_open_opportunities"]}[Data],
  #"Renamed columns" = Table.RenameColumns(#"Navigation 2",{{"opportunity_number", "Opportunity Number"}, {"opp_naming", "Opp. Naming"}, {"main_customer", "Main Customer"}, {"sales_organization", "Sales Organization"}, {"business_unit", "Business Unit"}, {"opportunity_type", "Opportunity Type"}, {"placement_type", "Placement Type"}, {"funnel_stage", "Funnel Stage"}, {"created_by", "Created by"}, {"solution", "Solution"}, {"success", "Success"}, {"estimated_closing_date", "Estimated Closing Date"}, {"affected_mycompany", "Affected Mycompany"}, {"affected_competitor", "Affected Competitor"}, {"offered_mycompany_and_mycompany_indirect", "Offered Mycompany & Mycompany Indirect"}, {"offered_qty_mycompany_and_mycompany_indirect", "Offered Qty Mycompany & Mycompany Indirect"}})
in
  #"Renamed columns";
shared #"Closed Opp" = let
  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),
  #"Navigation 1" = Source{[Name = "compliance"]}[Data],
  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_closed_opportunities"]}[Data],
  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"opportunity_number", "Opportunity Number"}, {"opp_naming", "Opp. Naming"}, {"main_customer", "Main Customer"}, {"sales_organization", "Sales Organization"}, {"business_unit", "Business Unit"}, {"opportunity_type", "Opportunity Type"}, {"placement_type", "Placement Type"}, {"funnel_stage", "Funnel Stage"}, {"created_by", "Created by"}, {"solution", "Solution"}, {"affected_mycompany", "Afected Mycompany"}, {"offered_mycompany_and_mycompany_indirect", "Offered Mycompany & Mycompany Indirect"}, {"min_offered_competitor", "Min Offered competitor"}, {"max_offered_competitor", "Max Offered cometitor"}})
in
  #"Renamed columns";
"""
    block = _extract_entity_block("01_Events", document)
    assert block is not None
    assert "Source = AmazonRedshift.Database" in block
    assert "compliance" in block
    assert "cmp_events_master" in block


def test__extract_entity_block_complex_source_references_another():
    """When an entity's source references another shared entity.

    Handle a case when an entity's source references another shared entity in the same
    document.
    """
    document = """
section Section1;
shared Source = let
    Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com","somedb"),
    human_resources = Source{[Name="human_resources"]}[Data]
in
    human_resources;
shared workforce_data = let
  Source = Source,
  Navigation = Source{[Name = "workforce_data"]}[Data]
in
  Navigation;
shared hr_workforce_report_accesses = let
  Source = Source,
  Navigation = Source{[Name = "hr_workforce_report_accesses"]}[Data]
in
  Navigation;
"""
    block = _extract_entity_block("workforce_data", document)
    assert block is not None
    assert "Source = AmazonRedshift.Database" in block
    # The parent shared Source in this document defines human_resources as the schema
    # and the workforce_data entity references the workforce_data table.
    assert "human_resources" in block
    assert "workforce_data" in block


def test__extract_entity_block_not_found():
    document = """
section Section1;
shared SomeEntity = let
  Source = AmazonRedshift.Database("host", "db", []),
  #"Navigation 1" = Source{[Name = "schema"]}[Data],
  #"Navigation 2" = #"Navigation 1"{[Name = "table"]}[Data]
in
  #"Navigation 2";
"""
    block = _extract_entity_block("NonExistent", document)
    assert block is None


def test__extract_model_from_dataflow_entity_block():
    document = """
section Section1;
shared MyEntity = let
  Source = AmazonRedshift.Database("host", "db", []),
  #"Navegacion 1" = Source{[Name = "my_schema"]}[Data],
  #"Navegacion 2" = #"Navegacion 1"{[Name = "my_table"]}[Data]
in
  #"Navegacion 2";
"""
    entity_block = _extract_entity_block("MyEntity", document)
    assert entity_block is not None
    model = _extract_model_from_dataflow_entity_block(entity_block)
    assert model == {
        "name": "my_table",
        "schema": "my_schema",
        "database": "db",
        "tags": [{"source_system": "AmazonRedshift:Dataflow"}],
    }


def test__extract_model_from_dataflow_entity_block_complex():
    document = """
section Section1;
shared Source = let
    Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com","somedb"),
    human_resources = Source{[Name="human_resources"]}[Data]
in
    human_resources;
shared workforce_data = let
  Source = Source,
  Navigation = Source{[Name = "workforce_data"]}[Data]
in
  Navigation;
shared hr_workforce_report_accesses = let
  Source = Source,
  Navigation = Source{[Name = "hr_workforce_report_accesses"]}[Data]
in
  Navigation;
"""
    entity_block = _extract_entity_block("workforce_data", document)
    assert entity_block is not None
    model = _extract_model_from_dataflow_entity_block(entity_block)
    assert model == {
        "name": "workforce_data",
        "schema": "human_resources",
        "database": "somedb",
        "tags": [{"source_system": "AmazonRedshift:Dataflow"}],
    }


def test__extract_dataflow_table_from_expression__dataset():
    """Test handling of case 2) from below."""
    table_expr = """
let
    Source = SourceNewStrategicDim,
   Table = Source{[entity="co_sales_org"]}[Data],
   Text = Table.TransformColumnTypes(Table, List.Transform(Table.ColumnNames(Table),each {_, type text} )),
    Trim = Table.TransformColumns(Text,List.Transform(Table.ColumnNames(Text), each {_, each Text.Trim(_), type text})),
    Null =  Table.ReplaceValue(Trim,"",null,Replacer.ReplaceValue,Table.ColumnNames(Trim)),
    Proper = Table.TransformColumnNames(Null, Text.Proper )
in
    Proper
"""

    dataflows_info = [
        DataflowDetails(**{
            "id": "f0947807-8752-4b3e-9bbb-495111628dcf",  # this matches the ID in the expression
            "name": "some-name",
            "description": "some-desc",
            "version": "v1",
            "modifiedTime": "2023-10-10T10:00:00Z",
            "entities": [
                {
                    "name": "co_sales_org",
                    "attributes": [
                        {"name": "sales_org_code", "dataType": "string"},
                        {"name": "call_id", "dataType": "string"},
                    ],
                },
                {
                    "name": "another_entity",
                    "attributes": [
                        {"name": "Col1", "dataType": "string"},
                        {"name": "Col2", "dataType": "string"},
                    ],
                },
            ],
            "pbi:mashup": {
                "queriesMetadata": {},
                "document": 'section Section1;\r\nshared SourceMart = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  Navigation = Source{[Name = "commercial_ops"]}[Data]\r\nin\r\n  Navigation;\r\nshared InstallBudget = let\r\n  Source = SourceMart,\r\n  Navigation = Source{[Name = "commercial_ops_installed_base_budget"]}[Data]\r\nin\r\n  Navigation;\r\nshared InstallBase = let\n  Source = SourceMart,\n  Navigation = Source{[Name = "commercial_ops_installed_base"]}[Data],\n  Nulls = Table.ReplaceValue(Navigation,"",null,Replacer.ReplaceValue,Table.ColumnNames(Navigation)),\n  Proper = Table.TransformColumnNames(Nulls,Text.Proper)\n  \nin\n  Proper;\r\nshared Connectables = let\r\n  Source = SourceMart,\r\n  Navigation = Source{[Name = "commercial_ops_installed_base_connectables"]}[Data]\r\nin\r\n  Navigation;\r\nshared Connected = let\r\n  Source = SourceMart,\r\n  Navigation = Source{[Name = "commercial_ops_installed_base_connected"]}[Data]\r\nin\r\n  Navigation;\r\nshared #"Installed Base Mapping" = let\r\n  Source = SourceMart,\r\n  Navigation = Source{[Name = "commercial_ops_installed_base_mapping"]}[Data]\r\nin\r\n  Navigation;\r\nshared InstrumentsConnections = let\n  Source = SourceMart,\n  Navigation = Source{[Name = "co_instrument_dms_connections"]}[Data],\n  Chose = Table.SelectColumns(Navigation, {"material_number", "serial_number", "connected_material_number", "connected_serial_number", "connected_co_model"}),\n  RemoveDups = Table.Distinct(Chose),\n  InsId = Table.AddColumn(RemoveDups, "ins id", each [material_number] & "-" & [serial_number], type text),\n  DmsId = Table.AddColumn(InsId, "DMS Id", each [connected_material_number]&"-"&[connected_serial_number], type text),\r\n  ChoseCols = Table.SelectColumns(DmsId, {"connected_co_model", "ins id", "DMS Id"}),\r\n  FilterNull = Table.SelectRows(ChoseCols, each [connected_co_model] <> null and [connected_co_model] <> ""),\n  Proper = Table.TransformColumnNames (FilterNull,Text.Proper)\nin\n  Proper;\r\nshared SourceSandbox = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  Navigation = Source{[Name = "sandbox"]}[Data]\r\nin\r\n  Navigation;\r\nshared co_customer = let\r\n  Source = SourceMart,\r\n  Navigation = Source{[Name = "co_customer"]}[Data]\r\nin\r\n  Navigation;\r\nshared co_material = let\r\n  Source = SourceMart,\r\n  Navigation = Source{[Name = "co_material"]}[Data]\r\nin\r\n  Navigation;\r\nshared co_product = let\r\n  Source = SourceMart,\r\n  Navigation = Source{[Name = "co_product"]}[Data]\r\nin\r\n  Navigation;\r\nshared co_sales_district = let\r\n  Source = SourceMart,\r\n  Navigation = Source{[Name = "co_sales_district"]}[Data]\r\nin\r\n  Navigation;\r\nshared co_sales_org = let\r\n  Source = SourceMart,\r\n  Navigation = Source{[Name = "commercial_ops_t001"]}[Data]\r\nin\r\n  Navigation;\r\nshared commercial_ops_product_line_mapping = let\r\n  Source = SourceMart,\r\n  Navigation = Source{[Name = "commercial_ops_product_line_mapping"]}[Data]\r\nin\r\n  Navigation;\r\nshared co_product_type = let\r\n  Source = SourceMart,\r\n  Navigation = Source{[Name = "co_zsd_protyt"]}[Data]\r\nin\r\n  Navigation;\r\nshared co_product_line = let\r\n  Source = SourceMart,\r\n  Navigation = Source{[Name = "co_zsd_prolit"]}[Data]\r\nin\r\n  Navigation;\r\nshared co_model = let\n  Source = SourceMart,\n  Navigation = Source{[Name = "co_model"]}[Data]\nin\n  Navigation;\r\n',
                "connectionOverrides": [],
            },
        })
    ]
    expected = {
        "name": "commercial_ops_t001",
        "schema": "commercial_ops",
        "database": "somedb",
        "tags": [{"source_system": "AmazonRedshift:Dataflow"}],
    }

    assert (
        _extract_dataflow_table_from_expression(
            table_expr, dataflows_info=dataflows_info
        )
        == expected
    )


def test__extract_dataflow_table_from_expression__table():
    """Test extracting of dataset tables from a table-level defined dataflow.

    There are two ways tables using PowerBI Dataflows can be defined:

    1) At the dataset table level, where the table's expression directly references
       the dataflow entity from which its data is sourced.
    2) At the dataset level, where so-called "sources" are defined inside a dataset's
      "expressions" section, referencing dataflow entities. In this case, dataset
      tables reference these "sources", which, in turn, reference dataflow entities.

    This test covers the first case.

    The way the function works, is it:

    - Extracts dataflow ID and entity name from the table's expression string
    - Walks through the provided dataflows info to find the dataflow's definition
    - Extracts the entity's M code block from the dataflow definition, using
      _extract_entity_block()
    - Extracts the model (schema, table, db) from the entity block using
      _extract_model_from_dataflow_entity_block()

    In other words, in the PowerBI table's expression, we only get a reference to a
    dataflow entity. To get the actual database model (schema, table, db) used by this
    PowerBI table, we need to look it up in the dataflow definition.

    As PowerBI API returns most of this information in an unstructured format, the
    extraction logic is based on some assumptions regarding eg. M code's structure,
    and might not work in all cases.
    """
    # Example used:
    # PowerBI dataset table: Activity_IR
    # dataflow ID: f0947807-8752-4b3e-9bbb-495111628dcf
    # dataflow entity: Activity_IR
    # database table the entity is based on: somedb.service.srv_zsv_zsrhd

    expr = 'let\n    Source = PowerPlatform.Dataflows(null),\n    Workspaces = Source{[Id="Workspaces"]}[Data],\n    #"1234-5678" = Workspaces{[workspaceId="1234-5678"]}[Data],\n    #"f0947807-8752-4b3e-9bbb-495111628dcf" = #"1234-5678"{[dataflowId="f0947807-8752-4b3e-9bbb-495111628dcf"]}[Data],\n    Activity_IR_ = #"f0947807-8752-4b3e-9bbb-495111628dcf"{[entity="Activity_IR",version=""]}[Data],\n    #"Added Custom" = Table.AddColumn(Activity_IR_, "activity_id", each [sales_org_code]&"-"&[contact_nr]),\n    #"Added Custom1" = Table.AddColumn(#"Added Custom", "activity_instrument_id", each [material_code]&"-"&[serial_id]),\n    #"Filtered Rows" = Table.SelectRows(#"Added Custom1", each ([deletion_flag] = "") and ([billing_code] <> ""))\nin\n    #"Filtered Rows"'
    dataflows_info = [
        DataflowDetails(**{
            "id": "f0947807-8752-4b3e-9bbb-495111628dcf",  # this matches the ID in the expression
            "name": "some-name",
            "description": "some-desc",
            "version": "v1",
            "modifiedTime": "2023-10-10T10:00:00Z",
            "entities": [
                {
                    "name": "co_sales_org",
                    "attributes": [
                        {"name": "sales_org_code", "dataType": "string"},
                        {"name": "call_id", "dataType": "string"},
                    ],
                },
                {
                    "name": "another_entity",
                    "attributes": [
                        {"name": "Col1", "dataType": "string"},
                        {"name": "Col2", "dataType": "string"},
                    ],
                },
            ],
            "pbi:mashup": {
                "queriesMetadata": {},
                "document": 'section Section1;\r\nshared Statistics = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  #"Navigation 1" = Source{[Name = "service"]}[Data],\r\n  #"Navigation 2" = #"Navigation 1"{[Name = "srv_zsv_insd"]}[Data]\r\nin\r\n  #"Navigation 2";\r\nshared Instruments_Master = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  #"Navigation 1" = Source{[Name = "service"]}[Data],\r\n  #"Navigation 2" = #"Navigation 1"{[Name = "srv_zsv_zequi"]}[Data]\r\nin\r\n  #"Navigation 2";\r\nshared Instruments_Location = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  #"Navigation 1" = Source{[Name = "service"]}[Data],\r\n  #"Navigation 2" = #"Navigation 1"{[Name = "srv_zsv_zequz"]}[Data]\r\nin\r\n  #"Navigation 2";\r\nshared Contracts = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  #"Navigation 1" = Source{[Name = "service"]}[Data],\r\n  #"Navigation 2" = #"Navigation 1"{[Name = "srv_zsv_zschd"]}[Data]\r\nin\r\n  #"Navigation 2";\r\nshared ServiceCalls = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  #"Navigation 1" = Source{[Name = "service"]}[Data],\r\n  #"Navigation 2" = #"Navigation 1"{[Name = "srv_zsv_zsnhd"]}[Data]\r\nin\r\n  #"Navigation 2";\r\nshared ActivityDt_Material = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  #"Navigation 1" = Source{[Name = "service"]}[Data],\r\n  #"Navigation 2" = #"Navigation 1"{[Name = "srv_zsv_zsrdt"]}[Data]\r\nin\r\n  #"Navigation 2";\r\nshared Activity_IR = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  #"Navigation 1" = Source{[Name = "service"]}[Data],\r\n  #"Navigation 2" = #"Navigation 1"{[Name = "srv_zsv_zsrhd"]}[Data]\r\nin\r\n  #"Navigation 2";\r\nshared ActivityDt_Time = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  #"Navigation 1" = Source{[Name = "service"]}[Data],\r\n  #"Navigation 2" = #"Navigation 1"{[Name = "srv_zsv_zsrte"]}[Data]\r\nin\r\n  #"Navigation 2";\r\n',
                "connectionOverrides": [],
            },
        })
    ]
    expected = {
        "name": "srv_zsv_zsrhd",
        "schema": "service",
        "database": "somedb",
        "tags": [{"source_system": "AmazonRedshift:Dataflow"}],
    }

    assert (
        _extract_dataflow_table_from_expression(expr, dataflows_info=dataflows_info)
        == expected
    )


def test__extract_dataflow_table_from_expression__table_multiple_entities():
    expr = 'let\n    Source = PowerPlatform.Dataflows(null),\n    Workspaces = Source{[Id="Workspaces"]}[Data],\n    #"9876-5432" = Workspaces{[workspaceId="9876-5432"]}[Data],\n    #"53ba4055-a294-43c2-bd62-69d76c769b62" = #"9876-5432"{[dataflowId="53ba4055-a294-43c2-bd62-69d76c769b62"]}[Data],\n    #"01_Events_" = #"53ba4055-a294-43c2-bd62-69d76c769b62"{[entity="01_Events",version=""]}[Data],\n    #"Tipo cambiado" = Table.TransformColumnTypes(#"01_Events_",{{"ID Evento", Int64.Type}, {"Evento descripci\u00f3n", type text}, {"Organizaci\u00f3n ventas", type text}, {"Inicio de validez", type date}, {"Fin de validez", type date}, {"Tipo de evento", Int64.Type}, {"Proyecto", type text}, {"Grupo Divisi\u00f3n", type text}, {"Divisi\u00f3n", type text}, {"Grouping Code", type text}, {"Poblaci\u00f3n", type text}, {"Clave de pa\u00eds", type text}, {"N\u00famero de staff", Int64.Type}, {"N\u00famero invitados", Int64.Type}, {"Creado por", type text}, {"Creado el", type date}, {"Hora", type datetime}, {"Modificado por", type text}, {"Modificado el", type date}})\nin\n    #"Tipo cambiado"'
    dataflows_info = [
        DataflowDetails(**{
            "id": "53ba4055-a294-43c2-bd62-69d76c769b62",
            "name": "Analytics Interactions",
            "description": "",
            "version": "1.0",
            "culture": "en-US",
            "modifiedTime": "2025-07-14T08:53:06.548295+00:00",
            "ppdf:outputFileFormat": "csv",
            "pbi:mashup": {
                "fastCombine": False,
                "allowNativeQueries": False,
                "skipAutomaticHeaderAndTypeDetection": False,
                "queriesMetadata": {
                    "02_Activities": {
                        "queryId": "e0eca199-0c9a-4200-aa9e-6456e7cc9917",
                        "queryName": "02_Activities",
                        "loadEnabled": True,
                    },
                    "BU&Geographies": {
                        "queryId": "8ab9c9a0-3278-4b32-bb29-849af6ea9271",
                        "queryName": "BU&Geographies",
                        "loadEnabled": True,
                    },
                    "09_T&E": {
                        "queryId": "f3bdd11c-c1b7-4d2b-8c9d-23078a3328ff",
                        "queryName": "09_T&E",
                        "loadEnabled": True,
                    },
                    "08_Cuentas": {
                        "queryId": "74d63749-ffc3-4a35-964a-9792011f17fa",
                        "queryName": "08_Cuentas",
                        "loadEnabled": True,
                    },
                    "05_Event Type": {
                        "queryId": "90fb4ad4-c0e9-42ca-8285-f49d84851928",
                        "queryName": "05_Event Type",
                        "loadEnabled": True,
                    },
                    "Ingreso/Gasto": {
                        "queryId": "387261a0-2602-4b63-b25c-2b9dbcb34020",
                        "queryName": "Ingreso/Gasto",
                        "loadEnabled": True,
                    },
                    "Mapping": {
                        "queryId": "fd0895a5-dfbf-4f78-b211-bf957b92f475",
                        "queryName": "Mapping",
                        "loadEnabled": True,
                    },
                    "InGr Mapping": {
                        "queryId": "9ed92130-5474-434a-bee9-6c085d711850",
                        "queryName": "InGr Mapping",
                        "loadEnabled": True,
                    },
                    "Industry Group": {
                        "queryId": "a511cdb8-6851-4a97-90e9-c7d60ca3cbab",
                        "queryName": "Industry Group",
                        "loadEnabled": True,
                    },
                    "06_Interaction Type": {
                        "queryId": "4914cd75-24ca-46b0-9eab-edc7088fac4c",
                        "queryName": "06_Interaction Type",
                        "loadEnabled": True,
                    },
                    "03_Interactions": {
                        "queryId": "b808df91-dba6-450b-b837-54b24e2d54ab",
                        "queryName": "03_Interactions",
                        "loadEnabled": True,
                    },
                    "10_Tabla ZESE": {
                        "queryId": "be5cbdd2-98ce-406f-978c-1e968633488e",
                        "queryName": "10_Tabla ZESE",
                        "loadEnabled": True,
                    },
                    "01_Events": {
                        "queryId": "efc9e65c-f58a-4793-b0c0-6d79c1efc4ad",
                        "queryName": "01_Events",
                        "loadEnabled": True,
                    },
                    "04_Expenses": {
                        "queryId": "349f25b9-53a9-4e47-97ee-6c55a44dd7a5",
                        "queryName": "04_Expenses",
                        "loadEnabled": True,
                    },
                    "companies": {
                        "queryId": "855407b3-805e-4f89-8096-482ebbeabc20",
                        "queryName": "companies",
                        "loadEnabled": True,
                    },
                    "mastercalendar": {
                        "queryId": "6c9e461c-098b-425c-b271-a2166e1d4db7",
                        "queryName": "mastercalendar",
                        "loadEnabled": True,
                    },
                    "07_Contabilidad": {
                        "queryId": "6e892a1c-87a9-47b7-89cc-dd9e5ce594e2",
                        "queryName": "07_Contabilidad",
                        "loadEnabled": True,
                    },
                    "Open Opp": {
                        "queryId": "c5e1d108-5eb8-41c1-a586-89f5d53a983c",
                        "queryName": "Open Opp",
                        "loadEnabled": True,
                    },
                    "Closed Opp": {
                        "queryId": "ba41da0f-ee9e-4fd6-8f23-409b0d424645",
                        "queryName": "Closed Opp",
                        "loadEnabled": True,
                    },
                },
                "document": 'section Section1;\r\nshared #"02_Activities" = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  #"Navigation 1" = Source{[Name = "compliance"]}[Data],\r\n  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_activities_master"]}[Data],\r\n  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"id_evento", "ID Evento"}, {"id_actividad", "ID Actividad"}, {"actividad_descripcion", "Actividad descripci\u00f3n"}, {"tipo_de_actividad", "Tipe de actividad"}, {"inicio_de_validez", "Inicio de validez"}, {"fin_de_validez", "Fin de validez"}, {"hora_inicio_actividad", "Hora inicio actividad"}, {"hora_fin_actividad", "Hora fin actividad"}, {"creado_por", "Creado por"}, {"creado_el", "Creado el"}, {"hora", "Hora"}, {"modificado_por", "Modificado por"}, {"modificado_el", "Modificado el"}, {"hora_modificacion", "Hora modificaci\u00f3n"}})\r\nin\r\n  #"Renamed columns";\r\nshared #"BU&Geographies" = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  #"Navigation 1" = Source{[Name = "compliance"]}[Data],\r\n  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_bu_geographies"]}[Data],\r\n  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"sociedad", "Sociedad"}, {"code", "Code"}, {"name", "Name"}, {"grupo", "Grupo"}, {"bu", "BU"}, {"geography", "Geography"}})\r\nin\r\n  #"Renamed columns";\r\nshared #"09_T&E" = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  #"Navigation 1" = Source{[Name = "compliance"]}[Data],\r\n  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_concur_te"]}[Data],\r\n  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"employee_id", "Employee ID"}, {"employee_and_id", "Employee + ID"}, {"no_times", "N\u00ba Times"}, {"report_name", "Report Name"}, {"submit_date", "Submit Date"}, {"total_approved_amount_rpt", "Total Approved Amount (rpt)"}, {"transaction_date", "Transaction Date"}, {"expense_type", "Expense Type"}, {"vendor", "Vendor"}, {"purpose", "Purpose"}, {"payment_type", "Payment Type"}, {"approved_amount_rpt", "Approved Amount (rpt)"}, {"attendee", "Attendee"}, {"title", "Title"}, {"company", "Company"}, {"type", "Type"}, {"amount", "Amount"}}),\r\n  Custom = Table.TransformColumnTypes(Table.AddColumn(#"Renamed columns", "ZESE", each Text.Start([Employee ID], 3)), {{"ZESE", type text}})\r\nin\r\n  Custom;\r\nshared #"08_Cuentas" = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  #"Navigation 1" = Source{[Name = "compliance"]}[Data],\r\n  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_cuentas_master"]}[Data],\r\n  Custom = Table.RenameColumns(#"Navigation 2", {{"cuentas", "Cuentas"}, {"descripcion", "Descripci\u00f3n"}})\r\nin\r\n  Custom;\r\nshared #"05_Event Type" = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  #"Navigation 1" = Source{[Name = "compliance"]}[Data],\r\n  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_event_type"]}[Data],\r\n  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"event_type", "Event type"}, {"description", "Description"}})\r\nin\r\n  #"Renamed columns";\r\nshared #"Ingreso/Gasto" = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  #"Navigation 1" = Source{[Name = "compliance"]}[Data],\r\n  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_grupos_master"]}[Data],\r\n  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"cuenta", "Cuenta"}, {"grupo", "Grupo"}})\r\nin\r\n  #"Renamed columns";\r\nshared Mapping = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  #"Navigation 1" = Source{[Name = "compliance"]}[Data],\r\n  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_hcp_partner_mapping"]}[Data],\r\n  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"hcp_partner_id", "HCP Partner ID"}, {"main_customer", "Main Customer"}})\r\nin\r\n  #"Renamed columns";\r\nshared #"InGr Mapping" = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  #"Navigation 1" = Source{[Name = "compliance"]}[Data],\r\n  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_industry_group_mapping"]}[Data],\r\n  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"ing", "InG"}, {"industry_group", "Industry Group"}, {"classification", "Classification"}})\r\nin\r\n  #"Renamed columns";\r\nshared #"Industry Group" = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  #"Navigation 1" = Source{[Name = "compliance"]}[Data],\r\n  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_industry_group_sales"]}[Data],\r\n  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"year", "Year"}, {"code", "Code"}, {"sales_organization", "Sales Organization"}, {"ing", "InG"}, {"industry_group", "Industry Group"}, {"sales", "Sales"}})\r\nin\r\n  #"Renamed columns";\r\nshared #"06_Interaction Type" = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  #"Navigation 1" = Source{[Name = "compliance"]}[Data],\r\n  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_interaction_type"]}[Data],\r\n  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"interaction_type", "Interaction Type"}, {"language", "Language"}, {"name", "Name"}})\r\nin\r\n  #"Renamed columns";\r\nshared #"03_Interactions" = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  #"Navigation 1" = Source{[Name = "compliance"]}[Data],\r\n  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_interactions_master"]}[Data],\r\n  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"id_evento", "ID Evento"}, {"id_actividad", "ID Actividad"}, {"id_nteraccion", "ID Interacci\u00f3n"}, {"hcp_partner_id", "HCP Partner ID"}, {"tipo_de_hcp_partner", "Tipo de HCP partner"}, {"prestacion_de_servicio", "Prestaci\u00f3n de servicio"}, {"tipo_de_interaccion", "Tipo de interacci\u00f3n"}, {"hco_employer_id", "HCO Employer ID"}, {"creado_por", "Creado por"}, {"creado_el", "Creado el"}, {"hora", "Hora"}, {"modificado_por", "Modificado por"}, {"modificado_el", "Modificado el"}, {"hora_modificacion", "Hora modificaci\u00f3n"}})\r\nin\r\n  #"Renamed columns";\r\nshared #"10_Tabla ZESE" = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  #"Navigation 1" = Source{[Name = "compliance"]}[Data],\r\n  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_zeses"]}[Data],\r\n  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"zese", "ZESE"}, {"mycompany_company", "MycompanyCompany"}, {"code", "Code"}, {"sociedad", "Sociedad"}})\r\nin\r\n  #"Renamed columns";\r\nshared #"01_Events" = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  #"Navigation 1" = Source{[Name = "compliance"]}[Data],\r\n  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_events_master"]}[Data],\r\n  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"id_evento", "ID Evento"}, {"evento_descripcion", "Evento descripci\u00f3n"}, {"organizacion_ventas", "Organizaci\u00f3n ventas"}, {"inicio_de_validez", "Inicio de validez"}, {"fin_de_validez", "Fin de validez"}, {"tipo_de_evento", "Tipo de evento"}, {"proyecto", "Proyecto"}, {"modificado_el", "Modificado el"}, {"modificado_por", "Modificado por"}, {"hora", "Hora"}, {"creado_el", "Creado el"}, {"creado_por", "Creado por"}, {"numero_invitados", "N\u00famero invitados"}, {"numero_de_staff", "N\u00famero de staff"}, {"clave_de_pais", "Clave de pa\u00eds"}, {"poblacion", "Poblaci\u00f3n"}, {"grouping_code", "Grouping Code"}, {"grupo_division", "Grupo Divisi\u00f3n"}, {"division", "Divisi\u00f3n"}})\r\nin\r\n  #"Renamed columns";\r\nshared #"04_Expenses" = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  #"Navigation 1" = Source{[Name = "compliance"]}[Data],\r\n  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_expenses_master"]}[Data],\r\n  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"id_evento", "ID Evento"}, {"id_actividad", "ID Actividad"}, {"id_interaccion", "ID Interacci\u00f3n"}, {"posicion_gastos", "Posici\u00f3n gastos"}, {"hcp_partner_id", "HCP Partner ID"}, {"tipo_de_hcp_partner", "Tipo de HCP partner"}, {"transparencia", "Transparencia"}, {"concepto_de_gasto", "Concepto de gasto"}, {"acreedor", "Acreedor"}, {"fecha_factura", "Fecha factura"}, {"base_p_plazo_pago", "Base p.plazo pago"}, {"valor_neto", "Valor neto"}, {"moneda", "Moneda"}, {"impte_impto_mon_loc", "Impte.impto.mon.loc."}, {"percentaje", "Porcentaje"}, {"cuenta_de_mayor", "Cuenta de mayor"}, {"centro_de_coste", "Centro de coste"}, {"ejercicio", "Ejercicio"}, {"no_documento", "N\u00ba documento"}, {"creado_por", "Creado por"}, {"creado_el", "Creado el"}, {"hora", "Hora"}, {"modificado_por", "Modificado por"}, {"modificado_el", "Modificado el"}, {"hora_modificacion", "Hora modificaci\u00f3n"}, {"exchange_rate", "Currency Rates.Exchange rate"}})\r\nin\r\n  #"Renamed columns";\r\nshared companies = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  #"Navigation 1" = Source{[Name = "compliance"]}[Data],\r\n  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_sales_companies"]}[Data],\r\n  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"sales_organization", "Sales Organization"}, {"sociedad", "Sociedad"}, {"code", "Code"}})\r\nin\r\n  #"Renamed columns";\r\nshared mastercalendar = let\n    StartDate = #date(2016,1,1),\n    EndDate = #date(2025,12,31),\n    NumberOfDays = Duration.Days( EndDate - StartDate ),\n    Dates = List.Dates(StartDate, NumberOfDays+1, #duration(1,0,0,0)),\n    #"Converted to Table" = Table.FromList(Dates, Splitter.SplitByNothing(), null, null, ExtraValues.Error),\n    #"Renamed Columns" = Table.RenameColumns(#"Converted to Table",{{"Column1", "FullDateAlternateKey"}}),\n    #"Changed Type" = Table.TransformColumnTypes(#"Renamed Columns",{{"FullDateAlternateKey", type date}}),\n    #"Inserted Year" = Table.AddColumn(#"Changed Type", "A\u00f1o", each Date.Year([FullDateAlternateKey]), type number),\n    #"Inserted Month" = Table.AddColumn(#"Inserted Year", "Mes Num", each Date.Month([FullDateAlternateKey]), type number),\n    #"Inserted Month Name" = Table.AddColumn(#"Inserted Month", "Mes", each Date.MonthName([FullDateAlternateKey]), type text),\n    #"Inserted Quarter" = Table.AddColumn(#"Inserted Month Name", "Trimestre", each Date.QuarterOfYear([FullDateAlternateKey]), type number),\n    #"Inserted Week of Year" = Table.AddColumn(#"Inserted Quarter", "Semana del a\u00f1o", each Date.WeekOfYear([FullDateAlternateKey]), type number),\n    #"Inserted Week of Month" = Table.AddColumn(#"Inserted Week of Year", "Semana del mes", each Date.WeekOfMonth([FullDateAlternateKey]), type number),\n    #"Inserted Day" = Table.AddColumn(#"Inserted Week of Month", "Dia Num", each Date.Day([FullDateAlternateKey]), type number),\n    #"Inserted Day of Week" = Table.AddColumn(#"Inserted Day", "Dia de la semana", each Date.DayOfWeek([FullDateAlternateKey]), type number),\n    #"Inserted Day of Year" = Table.AddColumn(#"Inserted Day of Week", "Dia del a\u00f1o", each Date.DayOfYear([FullDateAlternateKey]), type number),\n    #"Inserted Day Name" = Table.AddColumn(#"Inserted Day of Year", "Dia", each Date.DayOfWeekName([FullDateAlternateKey]), type text),\n    #"Columnas con nombre cambiado" = Table.RenameColumns(#"Inserted Day Name",{{"FullDateAlternateKey", "Fecha"}})\nin\n    #"Columnas con nombre cambiado";\r\nshared #"07_Contabilidad" = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  #"Navigation 1" = Source{[Name = "compliance"]}[Data],\r\n  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_contabilidad"]}[Data],\r\n  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"cuenta", "Cuenta"}, {"asignacion", "Asignaci\u00f3n"}, {"fe_contabilizacion", "Fe.contabilizaci\u00f3n"}, {"importe_en_moneda_local", "Importe en moneda local"}, {"texto", "Texto"}, {"sociedad", "Sociedad"}})\r\nin\r\n  #"Renamed columns";\r\nshared #"Open Opp" = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  #"Navigation 1" = Source{[Name = "compliance"]}[Data],\r\n  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_open_opportunities"]}[Data],\r\n  #"Renamed columns" = Table.RenameColumns(#"Navigation 2",{{"opportunity_number", "Opportunity Number"}, {"opp_naming", "Opp. Naming"}, {"main_customer", "Main Customer"}, {"sales_organization", "Sales Organization"}, {"business_unit", "Business Unit"}, {"opportunity_type", "Opportunity Type"}, {"placement_type", "Placement Type"}, {"funnel_stage", "Funnel Stage"}, {"created_by", "Created by"}, {"solution", "Solution"}, {"success", "Success"}, {"estimated_closing_date", "Estimated Closing Date"}, {"affected_mycompany", "Affected Mycompany"}, {"affected_competitor", "Affected Competitor"}, {"offered_mycompany_and_mycompany_indirect", "Offered Mycompany & Mycompany Indirect"}, {"offered_qty_mycompany_and_mycompany_indirect", "Offered Qty Mycompany & Mycompany Indirect"}})\r\nin\r\n  #"Renamed columns";\r\nshared #"Closed Opp" = let\r\n  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", [ProviderName = null, BatchSize = null]),\r\n  #"Navigation 1" = Source{[Name = "compliance"]}[Data],\r\n  #"Navigation 2" = #"Navigation 1"{[Name = "cmp_closed_opportunities"]}[Data],\r\n  #"Renamed columns" = Table.RenameColumns(#"Navigation 2", {{"opportunity_number", "Opportunity Number"}, {"opp_naming", "Opp. Naming"}, {"main_customer", "Main Customer"}, {"sales_organization", "Sales Organization"}, {"business_unit", "Business Unit"}, {"opportunity_type", "Opportunity Type"}, {"placement_type", "Placement Type"}, {"funnel_stage", "Funnel Stage"}, {"created_by", "Created by"}, {"solution", "Solution"}, {"affected_mycompany", "Afected Mycompany"}, {"offered_mycompany_and_mycompany_indirect", "Offered Mycompany & Mycompany Indirect"}, {"min_offered_competitor", "Min Offered competitor"}, {"max_offered_competitor", "Max Offered cometitor"}})\r\nin\r\n  #"Renamed columns";\r\n',
                "connectionOverrides": [
                    {
                        "path": "redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com;somedb",
                        "kind": "AmazonRedshift",
                        "provider": "CdsA",
                        "authenticationKind": None,
                        "environmentName": None,
                        "apiName": None,
                        "connectionName": "8032a079-1c29-4b2d-bca4-bfa0788be8c5",
                        "audience": None,
                    }
                ],
            },
        })
    ]
    expected = {
        "name": "cmp_events_master",
        "schema": "compliance",
        "database": "somedb",
        "tags": [{"source_system": "AmazonRedshift:Dataflow"}],
    }

    assert (
        _extract_dataflow_table_from_expression(expr, dataflows_info=dataflows_info)
        == expected
    )


def test_extract_tables_direct_and_named_source():
    """Integration-like test for extract_tables().

    Covers three scenarios in one workspace:
    - dataset table expression referencing a dataflow (has dataflowId).
    - dataset table expression that references a named source which contains an
      entity reference.
    - a real-world style dataflow entity that defines Source via Table.Combine
      of several shared steps (co_fact_pnl_by_customer).
    """
    # Direct dataflow reference expression (contains dataflowId and entity)
    expr_direct = (
        "let\n"
        "    Source = PowerPlatform.Dataflows(null),\n"
        '    Workspaces = Source{[Id="Workspaces"]}[Data],\n'
        '    #"df-direct-ws" = Workspaces{[workspaceId="ws"]}[Data],\n'
        '    #"df-direct" = #"df-direct-ws"{[dataflowId="df-direct"]}[Data],\n'
        '    EntityDirect_ = #"df-direct"{[entity="EntityDirect",version=""]}[Data],\n'
        "in\n"
        "    EntityDirect_"
    )

    # Named-source-style expression (no dataflowId, but contains entity token)
    expr_named = (
        "let\n"
        "    Source = SourceNewStrategicDim,\n"
        '    Table = Source{[entity="co_customer"]}[Data],\n'
        "in\n"
        "    Table"
    )

    # co_fact example named-source expression
    expr_cofact = (
        "let\n"
        "    Source = SourceDataFlowFactPnL,\n"
        '    Table = Source{[entity="co_fact_pnl_by_customer"]}[Data],\n'
        "in\n"
        "    Table"
    )

    # Build a minimal workspace_info with three datasets/tables
    workspace = {
        "workspaces": [
            {
                "id": "ws1",
                "name": "WS1",
                "state": "Active",
                "reports": [],
                "dashboards": [],
                "users": [],
                "datasets": [
                    {
                        "id": "ds-direct",
                        "name": "DS Direct",
                        "createdDate": "2025-01-01",
                        "tables": [
                            {
                                "name": "table_direct",
                                "isHidden": False,
                                "columns": [
                                    {
                                        "name": "id",
                                        "dataType": "string",
                                        "isHidden": False,
                                        "columnType": "Data",
                                    }
                                ],
                                "measures": [],
                                "source": [{"expression": expr_direct}],
                            }
                        ],
                    },
                    {
                        "id": "ds-named",
                        "name": "DS Named",
                        "createdDate": "2025-01-01",
                        "tables": [
                            {
                                "name": "table_named",
                                "isHidden": False,
                                "columns": [
                                    {
                                        "name": "id",
                                        "dataType": "string",
                                        "isHidden": False,
                                        "columnType": "Data",
                                    }
                                ],
                                "measures": [],
                                "source": [{"expression": expr_named}],
                            }
                        ],
                    },
                    {
                        "id": "ds-cofact",
                        "name": "DS CoFact",
                        "createdDate": "2025-01-01",
                        "tables": [
                            {
                                "name": "table_cofact",
                                "isHidden": False,
                                "columns": [
                                    {
                                        "name": "id",
                                        "dataType": "string",
                                        "isHidden": False,
                                        "columnType": "Data",
                                    }
                                ],
                                "measures": [],
                                "source": [{"expression": expr_cofact}],
                            }
                        ],
                    },
                ],
            }
        ]
    }

    workspace_info = WorkspaceInfo(**workspace)

    # Create three dataflows: direct-case, named-case, and the Table.Combine() case.
    dataflows_info = [
        DataflowDetails(**{
            "id": "df-direct",
            "name": "Direct DF",
            "description": "",
            "version": "1.0",
            "modifiedTime": "2025-01-01T00:00:00Z",
            "entities": [
                {
                    "name": "EntityDirect",
                    "attributes": [{"name": "col", "dataType": "string"}],
                }
            ],
            "pbi:mashup": {
                "queriesMetadata": {},
                "document": (
                    "section Section1;\n"
                    "shared EntityDirect = let\n"
                    '  Source = AmazonRedshift.Database("host.direct","db_direct"),\n'
                    '  Nav1 = Source{[Name="schema_direct"]}[Data],\n'
                    '  Nav2 = Nav1{[Name="table_direct_name"]}[Data]\n'
                    "in\n"
                    "  Nav2;"
                ),
                "connectionOverrides": [],
            },
        }),
        DataflowDetails(**{
            "id": "df-named",
            "name": "Named DF",
            "description": "",
            "version": "1.0",
            "modifiedTime": "2025-01-01T00:00:00Z",
            "entities": [
                {
                    "name": "co_customer",
                    "attributes": [{"name": "customer_id", "dataType": "string"}],
                }
            ],
            "pbi:mashup": {
                "queriesMetadata": {},
                "document": (
                    "section Section1;\n"
                    "shared SourceMart = let\n"
                    '  Source = AmazonRedshift.Database("host.named","db_named"),\n'
                    '  Navigation = Source{[Name = "commercial_ops"]}[Data]\n'
                    "in\n"
                    "  Navigation;\n"
                    "shared co_customer = let\n"
                    "  Source = SourceMart,\n"
                    '  Navigation = Source{[Name = "co_customer_schema"]}[Data],\n'
                    '  Final = Navigation{[Name = "co_customer_table"]}[Data]\n'
                    "in\n"
                    "  Final;"
                ),
                "connectionOverrides": [],
            },
        }),
        DataflowDetails(**{
            "id": "df-fact-pnl",
            "name": "Fact PnL DF",
            "description": "",
            "version": "1.0",
            "modifiedTime": "2025-01-01T00:00:00Z",
            "entities": [
                {
                    "name": "co_fact_pnl_by_customer",
                    "attributes": [{"name": "col", "dataType": "string"}],
                }
            ],
            "pbi:mashup": {
                "queriesMetadata": {},
                "document": (
                    "section Section1;\n"
                    "shared SourceTable = let\n"
                    '  Source = AmazonRedshift.Database("redshift-cluster.someaddr123.eu-west-1.redshift.amazonaws.com", "somedb", []),\n'
                    '  Navigation = Source{[Name = "commercial_ops"]}[Data],\n'
                    '  NavTable = Navigation{[Name = "co_fact_pnl_by_customer"]}[Data]\n'
                    "in\n"
                    "  NavTable;\n"
                    "shared CurrentYear = let\n"
                    "  Source = SourceTable,\n"
                    "  Filtered = Source\n"
                    "in\n"
                    "  Filtered;\n"
                    "shared OneYear = let\n"
                    "  Source = SourceTable\n"
                    "in\n"
                    "  Source;\n"
                    "shared co_fact_pnl_by_customer = let\n"
                    "  Source = Table.Combine({CurrentYear, OneYear})\n"
                    "in\n"
                    "  Source;\n"
                ),
                "connectionOverrides": [],
            },
        }),
    ]

    tables = extract_tables(workspace_info, dataflows_info)

    # There should be three extracted tables, one per dataset table we created.
    names = {t["dataset_table_name"]: t for t in tables}

    # Direct case.
    assert "table_direct" in names
    assert names["table_direct"]["database_table_name"] == "table_direct_name"
    assert names["table_direct"]["database_table_schema"] == "schema_direct"
    assert names["table_direct"]["database_table_database"] == "db_direct"

    # Named-source case.
    assert "table_named" in names
    assert names["table_named"]["database_table_name"] == "co_customer_table"
    # The extractor inlines the parent shared SourceMart, so the schema is taken
    # from the parent Navigation step (commercial_ops) rather than the child
    # Navigation variable name used locally in the co_customer block.
    assert names["table_named"]["database_table_schema"] == "commercial_ops"
    assert names["table_named"]["database_table_database"] == "db_named"

    # (Table.Combine) case.
    assert "table_cofact" in names
    assert names["table_cofact"]["database_table_name"] == "co_fact_pnl_by_customer"
    assert names["table_cofact"]["database_table_schema"] == "commercial_ops"
    assert names["table_cofact"]["database_table_database"] == "somedb"
