public/Import-SfMetadataModel.ps1

function Import-SfMetadataModel {

    <#
        .SYNOPSIS
        Imports a metadata model from Excel workbooks and/or CSV files.
    #>


    [CmdletBinding()]
    param (
        # Path to a .xlsx file, a .csv file, or a directory containing schema-named files.
        # Accepts pipeline input; multiple paths are accumulated into a single metadata model.
        [Parameter(Position = 0, ValueFromPipeline)]
        [string] $Path,

        # If Path is a directory, recurse into subdirectories.
        [Parameter()]
        [switch] $Recurse
    )

    begin {
        $ErrorActionPreference = 'Stop'
        [bool] $IsDebug   = $DebugPreference   -ne 'SilentlyContinue'
        [bool] $IsVerbose = $VerbosePreference -ne 'SilentlyContinue'

        Write-Verbose "ModuleRoot: $($Script:ModuleRoot)"

        # --- initialize model; schema is loaded inside New-SfMetadataModel
        $MetadataModel = New-SfMetadataModel

        # --- local helper: normalize and merge a single table into the model
        function AddToModel {
            param (
                [string] $TableName,
                [string] $Source,
                [array]  $Rows
            )
            $ConvertParams = @{
                Rows        = $Rows
                TableSchema = $MetadataModel.Schema[$TableName]
                Source      = $Source
            }
            [PSCustomObject[]] $NormalizedRows = ConvertTo-NormalizedModelTable @ConvertParams

            $MetadataModel.Tables[$TableName] += $NormalizedRows

            Write-Information "Imported: $Source ($($NormalizedRows.Count) rows)"
        }
    }

    process {

        # --- resolve input: single file or directory
        [array] $Files = if (Test-Path -Path $Path -PathType Leaf) {
            Get-Item -Path $Path
        }
        elseif ($Recurse) {
            Get-ChildItem -Path (Join-Path $Path '*') -Include '*.xlsx', '*.csv' -Recurse
        }
        else {
            Get-ChildItem -Path (Join-Path $Path '*') -Include '*.xlsx', '*.csv'
        }

        # --- check ImportExcel dependency if any .xlsx files are present
        if ($Files | Where-Object { $_.Extension -eq '.xlsx' }) {
            Assert-ModuleDependency -ModuleName 'ImportExcel'
        }

        # --- process each file
        foreach ($File in $Files) {

            if ($File.Extension -eq '.csv') {

                [string] $TableName = $File.BaseName
                if ($MetadataModel.Schema.ContainsKey($TableName)) {
                    AddToModel -TableName $TableName -Source $File.FullName -Rows (Import-Csv -Path $File.FullName)
                }
                else {
                    Write-Verbose "Skipped: $($File.FullName) (not in schema)"
                }
            }
            elseif ($File.Extension -eq '.xlsx') {

                foreach ($Worksheet in (Get-ExcelSheetInfo -Path $File.FullName)) {

                    [string] $TableName = $Worksheet.Name
                    if ($MetadataModel.Schema.ContainsKey($TableName)) {
                        AddToModel -TableName $TableName -Source "$($File.FullName)|$TableName" -Rows (Import-Excel -Path $File.FullName -WorksheetName $TableName)
                    }
                    else {
                        Write-Verbose "Skipped: $($File.FullName) / $TableName (not in schema)"
                    }
                }
            }
        }
    }

    end {
        return $MetadataModel
    }
}