diff --git a/Test/include/database.mock.config.ps1 b/Test/include/database.mock.config.ps1 new file mode 100644 index 0000000..2ff8965 --- /dev/null +++ b/Test/include/database.mock.config.ps1 @@ -0,0 +1,4 @@ + +# This file is part of the Database Mock Include. + +$DB_INVOKE_GET_ROOT_PATH_ALIAS = "CsvHelperGetDbRootPath" diff --git a/Test/include/database.mock.ps1 b/Test/include/database.mock.ps1 new file mode 100644 index 0000000..801f637 --- /dev/null +++ b/Test/include/database.mock.ps1 @@ -0,0 +1,48 @@ +# DATABASE MOCK +# +# This file is used to mock the database path and the database file +# for the tests. It creates a mock database path and a mock database file +# and sets the database path to the mock database path. +# We need to define variables for this include to work +# $MOCK_DATABASE_PATH : The path used as the mock database folder +# $DB_INVOKE_GET_ROOT_PATH_CMD : Invoke command that is needed to be mocked +# $DB_INVOKE_GET_ROOT_PATH_ALIAS : Invoke function to retreive the root path of the database +# +# Sample file +# # DATABASE MOCK VARIABLES +# # This file is required for DATABASE MOCK to work +# $DB_INVOKE_GET_ROOT_PATH_ALIAS = "MyModuleGetDbRootPath" +# + +$DB_INVOKE_GET_ROOT_PATH_CMD = "Invoke-$DB_INVOKE_GET_ROOT_PATH_ALIAS" +$MOCK_DATABASE_PATH = "test_database_path" + +function Mock_Database([switch]$ResetDatabase){ + + MockCallToString $DB_INVOKE_GET_ROOT_PATH_CMD -OutString "test_database_path" + + $dbstore = Invoke-MyCommand -Command $DB_INVOKE_GET_ROOT_PATH_CMD + Assert-AreEqual -Expected "test_database_path" -Presented $dbstore + + if($ResetDatabase){ + Reset-DatabaseStore + } + +} + +function Get-Mock_DatabaseStore{ + $dbstore = Invoke-MyCommand -Command $DB_INVOKE_GET_ROOT_PATH_CMD + return $dbstore +} + +function Reset-DatabaseStore{ + [CmdletBinding()] + param() + + $databaseRoot = Invoke-MyCommand -Command $DB_INVOKE_GET_ROOT_PATH_ALIAS + + Remove-Item -Path $databaseRoot -Recurse -Force -ErrorAction SilentlyContinue + + New-Item -Path $databaseRoot -ItemType Directory + +} \ No newline at end of file diff --git a/Test/include/invokeCommand.Mock.ps1 b/Test/include/invokeCommand.Mock.ps1 new file mode 100644 index 0000000..cd9cf19 --- /dev/null +++ b/Test/include/invokeCommand.Mock.ps1 @@ -0,0 +1,188 @@ + +# INVOKE COMMAND MOCK +# +# This includes help commands to mock invokes in a test module +# You need to set the following variables +# $MODULE_INVOKATION_TAG : name of the module that you are testing. This needs to match with the Tag used in the module you are testing. +# $MODULE_INVOKATION_TAG_MOCK : Tag for the mock functions on the testing moodule you are loading this include in +# MOCK_PATH : path to the mocks folder. This is where the mock files will be saved and loaded from. +# +# Sample: +# $MODULE_INVOKATION_TAG = "SfHelperModule" +# $MODULE_INVOKATION_TAG_MOCK = "SfHelperModule-Mock" +# $MOCK_PATH = $PSScriptRoot | Split-Path -Parent | Join-Path -ChildPath 'private' -AdditionalChildPath 'mocks' + + +function Set-InvokeCommandMock{ + [CmdletBinding()] + param( + [Parameter(Mandatory,Position=0)][string]$Alias, + [Parameter(Mandatory,Position=1)][string]$Command + ) + + InvokeHelper\Set-InvokeCommandAlias -Alias $Alias -Command $Command -Tag $MODULE_INVOKATION_TAG_MOCK +} + +function Reset-InvokeCommandMock{ + [CmdletBinding()] + param() + + # Remove all mocks + InvokeHelper\Reset-InvokeCommandAlias -Tag $MODULE_INVOKATION_TAG_MOCK + + # Disable all dependecies of the library + Disable-InvokeCommandAlias -Tag $MODULE_INVOKATION_TAG +} Export-ModuleMember -Function Reset-InvokeCommandMock + +function Enable-InvokeCommandAliasModule{ + [CmdletBinding()] + param() + + Enable-InvokeCommandAlias -Tag $MODULE_INVOKATION_TAG +} Export-ModuleMember -Function Enable-InvokeCommandAliasModule + +function MockCall{ + param( + [Parameter(Position=0)][string] $command, + [Parameter(Position=1)][string] $filename + ) + + Assert-MockFileNotfound $fileName + + Set-InvokeCommandMock -Alias $command -Command "Get-MockFileContent -filename $filename" +} + +function MockCallJson{ + param( + [Parameter(Position=0)][string] $command, + [Parameter(Position=1)][string] $filename + + ) + + Assert-MockFileNotfound $fileName + + Set-InvokeCommandMock -Alias $command -Command "Get-MockFileContentJson -filename $filename" +} + +function Get-MockFileFullPath{ + param( + [parameter(Mandatory,Position=0)][string] $fileName + ) + + $filePath = $MOCK_PATH | Join-Path -ChildPath $fileName + + return $filePath +} Export-ModuleMember -Function Get-MockFileFullPath + +function Get-MockFileContent{ + param( + [parameter(Mandatory,Position=0)][string] $fileName + ) + + Assert-MockFileNotfound $FileName + + $filePath = Get-MockFileFullPath -fileName $fileName + + $content = Get-Content -Path $filePath | Out-String + + return $content +} Export-ModuleMember -Function Get-MockFileContent + +function Get-MockFileContentJson{ + param( + [parameter(Mandatory,Position=0)][string] $fileName + ) + + Assert-MockFileNotfound $FileName + + $content = Get-MockFileContent -fileName $filename | ConvertFrom-Json + + return $content +} Export-ModuleMember -Function Get-MockFileContentJson + +function MockCallToString{ + param( + [Parameter(Position=0)][string] $command, + [Parameter(Position=1)][string] $OutString + ) + + $outputstring = 'echo "{output}"' + $outputstring = $outputstring -replace "{output}", $OutString + + Set-InvokeCommandMock -Alias $command -Command $outputstring +} + +function MockCallToNull{ + param( + [Parameter(Position=0)][string] $command + ) + + Set-InvokeCommandMock -Alias $command -Command 'return $null' +} + +function MockCallThrow{ + param( + [Parameter(Position=0)][string] $command, + [Parameter(Position=1)][string] $ExceptionMessage + + ) + + $mockCommand = 'throw "{message}"' + $mockCommand = $mockCommand -replace "{message}", $exceptionMessage + + Set-InvokeCommandMock -Alias $command -Command $mockCommand +} + +function Save-InvokeAsMockFile{ + param( + [Parameter(Mandatory=$true)] [string]$Command, + [Parameter(Mandatory=$true)] [string]$FileName, + [Parameter(Mandatory=$false)] [switch]$Force + ) + + $filePath = Get-MockFileFullPath -fileName $fileName + + $result = Invoke-Expression -Command $Command + + $json = $result | ConvertTo-Json -Depth 100 + + $json | Out-File -FilePath $filePath + + Write-Host $FileName +} Export-ModuleMember -Function Save-InvokeAsMockFile + +function Save-InvokeAsMockFileJson{ + param( + [Parameter(Mandatory=$true)] [string]$Command, + [Parameter(Mandatory=$true)] [string]$FileName + ) + + $filePath = Get-MockFileFullPath -fileName $fileName + + $result = Invoke-Expression -Command $Command + + $result | Out-File -FilePath $filePath + + Write-Host $FileName +} Export-ModuleMember -Function Save-InvokeAsMockFileJson + +function Assert-MockFileNotfound{ + param( + [Parameter(Mandatory=$true,Position=0)] [string]$FileName + ) + + $filePath = Get-MockFileFullPath -fileName $fileName + + if(-Not (Test-Path -Path $filePath)){ + throw "File not found: $fileName" + } + + # Throw if $file.name and the $filename parameter have different case + # We need to check this to avoid test bugs for mock files not found on linux that the FS is case sensitive + $file = Get-ChildItem -Path $MOCK_PATH | Where-Object { $_.Name.ToLower() -eq $fileName.ToLower() } + if($file.name -cne $fileName){ + Write-host "Wait-Debugger - File not found or wrong case - $($file.name)" + Wait-Debugger + throw "File not found or wrong case name. Expected[ $filename ] - Found[$( $file.name )]" + } +} \ No newline at end of file diff --git a/Test/private/NewCsvTestFile.ps1 b/Test/private/NewCsvTestFile.ps1 new file mode 100644 index 0000000..9baad43 --- /dev/null +++ b/Test/private/NewCsvTestFile.ps1 @@ -0,0 +1,21 @@ +function New-TestCsvFile { + param ( + [int]$NumRows = 10, + [string]$Path = "test.csv" + ) + + $data = @() + + for ($i = 1; $i -le $numRows; $i++) { + $data += [PSCustomObject]@{ + Id = "ValueId_$i" + Column1 = "Value1_$i" + Column2 = "Value2_$i" + Column3 = "Value3_$i" + } + } + + $data | Export-Csv -Path $Path -NoTypeInformation + + return $Path +} \ No newline at end of file diff --git a/Test/public/CsvFile.test.ps1 b/Test/public/CsvFile.test.ps1 new file mode 100644 index 0000000..8e55fbc --- /dev/null +++ b/Test/public/CsvFile.test.ps1 @@ -0,0 +1,49 @@ + +function Test_GetCsvFile{ + + Mock_Database -resetDatabase + $databaseRoot = Get-Mock_DatabaseStore + $csvPath = New-TestCsvFile + + # Act + $key = Import-CsvFile -Path $csvPath -KeyColumn "Column1" + + # Assert + Assert-IsNotNull -Object $key + Assert-Count -Expected 1 -Presented (Get-ChildItem -Path $databaseRoot) + Assert-ItemExist -Path "$databaseRoot/$key.json" + + # read database file from json + $data = Get-Content -Path "$databaseRoot/$key.json" | ConvertFrom-Json -Depth 10 -AsHashtable + + # Random record + $i = 5 + $record2 = $data["Value1_$i"] + + Assert-AreEqual -Expected "Value1_$i" -Presented $record2.Column1 + Assert-AreEqual -Expected "Value2_$i" -Presented $record2.Column2 + Assert-AreEqual -Expected "Value3_$i" -Presented $record2.Column3 +} + +function Test_GetCsvFile_Default_Id{ + + Mock_Database -resetDatabase + $databaseRoot = Get-Mock_DatabaseStore + $csvPath = New-TestCsvFile + + # Act + $key = Import-CsvFile -Path $csvPath + + # Assert + # read database file from json + $data = Get-Content -Path "$databaseRoot/$key.json" | ConvertFrom-Json -Depth 10 -AsHashtable + + # Random record + $i = 5 + $record2 = $data["ValueId_$i"] + + Assert-AreEqual -Expected "Value1_$i" -Presented $record2.Column1 + Assert-AreEqual -Expected "Value2_$i" -Presented $record2.Column2 + Assert-AreEqual -Expected "Value3_$i" -Presented $record2.Column3 +} + diff --git a/Test/public/CsvRecord.test.ps1 b/Test/public/CsvRecord.test.ps1 new file mode 100644 index 0000000..1c73dff --- /dev/null +++ b/Test/public/CsvRecord.test.ps1 @@ -0,0 +1,53 @@ + +function Test_GetCsvRecord{ + + Mock_Database -resetDatabase + + $csvPath = New-TestCsvFile + + $key = Import-CsvFile -Path $csvPath -KeyColumn "Column1" + + Assert-IsNotNull -Object $key + + # Act get record with csv with path + $record = Get-CsvRecord -Path $csvPath -KeyColumn "Column1" -Id "Value1_2" + + Assert-AreEqual -Expected "Value1_2" -Presented $record.Column1 + Assert-AreEqual -Expected "Value2_2" -Presented $record.Column2 + Assert-AreEqual -Expected "Value3_2" -Presented $record.Column3 + + # Call with Key + $record = Get-CsvRecord -Key $key -Id "Value1_3" + + Assert-AreEqual -Expected "Value1_3" -Presented $record.Column1 + Assert-AreEqual -Expected "Value2_3" -Presented $record.Column2 + Assert-AreEqual -Expected "Value3_3" -Presented $record.Column3 +} + +function Test_GetCsvRecord_Integration{ + + Mock_Database -resetDatabase + + $csvPath = New-TestCsvFile + + # Act get record with csv with path + $record = Get-CsvRecord -Path $csvPath -KeyColumn "Column1" -Id "Value1_2" + + Assert-AreEqual -Expected "Value1_2" -Presented $record.Column1 + Assert-AreEqual -Expected "Value2_2" -Presented $record.Column2 + Assert-AreEqual -Expected "Value3_2" -Presented $record.Column3 +} + +function Test_GetCsvRecord_Integration_Id{ + + Mock_Database -resetDatabase + + $csvPath = New-TestCsvFile + + # Act get record with csv with path + $record = Get-CsvRecord -Path $csvPath -Id "ValueId_2" + + Assert-AreEqual -Expected "Value1_2" -Presented $record.Column1 + Assert-AreEqual -Expected "Value2_2" -Presented $record.Column2 + Assert-AreEqual -Expected "Value3_2" -Presented $record.Column3 +} \ No newline at end of file diff --git a/Test/public/SampleFunctionTests.ps1 b/Test/public/SampleFunctionTests.ps1 deleted file mode 100644 index bb725bf..0000000 --- a/Test/public/SampleFunctionTests.ps1 +++ /dev/null @@ -1,29 +0,0 @@ -$TESTED_MODULE_PATH = $PSScriptRoot | split-path -Parent | split-path -Parent - -function Test_GetPublicString{ - - $sampleString = "this is a sample string" - - $result = Get-PublicString -Param1 $sampleString - - Assert-AreEqual -Expected ("Public string [{0}]" -f $samplestring) -presented $result -Comment "Sample test failed" - -} - -function Test_GetPrivateString { - - $testedModulePath = $TESTED_MODULE_PATH | Join-Path -ChildPath "CsvHelper.psd1" - $testedModule = Import-Module -Name $testedModulePath -Force -PassThru - - $sampleString = "this is a sample string" - - $result = & $testedModule { - $sampleString = "this is a sample string" - Get-PrivateString -Param1 $sampleString - } - - Assert-AreEqual -Expected ("Private string [{0}]" -f $samplestring) -presented $result -Comment "Sample test failed" - -} - -Export-ModuleMember -Function Test_* diff --git a/docs/readme.md b/docs/readme.md new file mode 100644 index 0000000..ce81d31 --- /dev/null +++ b/docs/readme.md @@ -0,0 +1,11 @@ +# CSV Helper + +This module helps enabling integratin with ProjectHelper to update GitHub projects with data from a CSV file. + +## Architecture + +```mermaid +flowchart TD +CsvRecord --> CsvDatabase --> CsvFile + +``` diff --git a/include/config.config.ps1 b/include/config.config.ps1 deleted file mode 100644 index c608cac..0000000 --- a/include/config.config.ps1 +++ /dev/null @@ -1,91 +0,0 @@ -# CONFIG - PUBLIC -# -# This script defines aliases and functions for configuration management specific to "MyModule". -# It is intended to be included in public-facing scripts. - -# Define unique aliases for "MyModule" -$CONFIG_INVOKE_GET_ROOT_PATH_ALIAS = "CsvGetConfigRootPath" -$CONFIG_INVOKE_GET_ROOT_PATH_CMD = "Invoke-CsvGetConfigRootPath" - -# Set the alias for the root path command -Set-MyInvokeCommandAlias -Alias $CONFIG_INVOKE_GET_ROOT_PATH_ALIAS -Command $CONFIG_INVOKE_GET_ROOT_PATH_CMD - -# Define the function to get the configuration root path -function Invoke-CsvHelperGetConfigRootPath { - [CmdletBinding()] - param() - - $configRoot = GetConfigRootPath - return $configRoot -} - -Export-ModuleMember -Function Invoke-CsvHelperGetConfigRootPath - -# Extra functions not needed by INCLUDE CONFIG - -function Get-CsvHelperConfig{ - [CmdletBinding()] - param() - - $config = Get-Configuration - - return $config -} Export-ModuleMember -Function Get-CsvHelperConfig - -function Save-CsvHelperConfig{ - [CmdletBinding()] - param( - [Parameter(Mandatory, ValueFromPipeline, Position = 0)][Object]$Config - ) - - return Save-Configuration -Config $Config -} Export-ModuleMember -Function Save-CsvHelperConfig - -function Open-CsvHelperConfig{ - [CmdletBinding()] - param() - - $path = GetConfigFile -Key "config" - - code $path - -} Export-ModuleMember -Function Open-CsvHelperConfig - -function Add-CsvHelperConfigAttribute{ - [CmdletBinding()] - param( - [Parameter(Mandatory,Position=0)][ValidateSet("Account", "User", "Opportunity")][string]$objectType, - - [Parameter(Mandatory, ValueFromPipeline, Position = 1)][string]$Attribute - - ) - - begin{ - $config = Get-Configuration - $configAttribute = ($objectType + "_attributes").ToLower() - - if(-Not $config){ - $config = @{} - } - - if(-Not $config.$configAttribute){ - $config.$configAttribute = @() - } - } - - process{ - $config.$configAttribute += $Attribute - } - - End{ - $ret = Save-Configuration -Config $config - if(-Not $ret){ - throw "Error saving configuration" - } - - $config = Get-CsvHelperConfig - Write-Output $config.$configAttribute - - } - -} Export-ModuleMember -Function Add-CsvHelperConfigAttribute diff --git a/include/config.ps1 b/include/config.ps1 deleted file mode 100644 index 07b249e..0000000 --- a/include/config.ps1 +++ /dev/null @@ -1,121 +0,0 @@ -# CONFIG -# -# Configuration management module -# -# Include design description -# This is the function ps1. This file is the same for all modules. -# Create a public psq with variables, Set-MyInvokeCommandAlias call and Invoke public function. -# Invoke function will call back `GetConfigRootPath` to use production root path -# Mock this Invoke function with Set-MyInvokeCommandAlias to set the Store elsewhere -# This ps1 has function `GetConfigFile` that will call `Invoke-MyCommand -Command $CONFIG_INVOKE_GET_ROOT_PATH_ALIAS` -# to use the store path, mocked or not, to create the final store file name. -# All functions of this ps1 will depend on `GetConfigFile` for functionality. -# -# TODO : Create a related public ps1 -# -# Create a related public ps1 -# 1. define $CONFIG_INVOKE_GET_ROOT_PATH_ALIAS. Make it unique. -# 2. define $CONFIG_INVOKE_GET_ROOT_PATH_CMD. Point to the invoke function that calls GetConfigRootPath to get the store path -# -# Sample code (replace "MyModule" with a unique module prefix): -# $CONFIG_INVOKE_GET_ROOT_PATH_ALIAS = "MyModuleGetConfigRootPath" -# $CONFIG_INVOKE_GET_ROOT_PATH_CMD = "Invoke-MyModuleGetConfigRootPath" -# -# Set-MyInvokeCommandAlias -Alias $CONFIG_INVOKE_GET_ROOT_PATH_ALIAS -Command $CONFIG_INVOKE_GET_ROOT_PATH_CMD -# -# function Invoke-MyModuleGetConfigRootPath{ -# $configRoot = GetConfigRootPath -# return $configRoot -# } Export-ModuleMember -Function Invoke-MyModuleGetConfigRootPath - - -$moduleRootPath = $PSScriptRoot | Split-Path -Parent -$moduleName = (Get-ChildItem -Path $moduleRootPath -Filter *.psd1 | Select-Object -First 1).BaseName -$CONFIG_ROOT = [System.Environment]::GetFolderPath('UserProfile') | Join-Path -ChildPath ".helpers" -AdditionalChildPath $moduleName, "config" - -# Create the config root if it does not exist -if(-Not (Test-Path $CONFIG_ROOT)){ - New-Item -Path $CONFIG_ROOT -ItemType Directory -} - -function GetConfigRootPath { - [CmdletBinding()] - param() - - $configRoot = $CONFIG_ROOT - return $configRoot -} - -function GetConfigFile { - [CmdletBinding()] - param( - [Parameter(Mandatory = $true, Position = 0)][string]$Key - ) - - $configRoot = Invoke-MyCommand -Command $CONFIG_INVOKE_GET_ROOT_PATH_ALIAS - $path = Join-Path -Path $configRoot -ChildPath "$Key.json" - return $path -} - -function Test-Configuration { - [CmdletBinding()] - param( - [Parameter(Position = 0)][string]$Key = "config" - ) - - $path = GetConfigFile -Key $Key - - return Test-Path $path -} - -function Get-Configuration { - [CmdletBinding()] - param( - [Parameter(Position = 0)][string]$Key = "config" - ) - - $path = GetConfigFile -Key $Key - - if(-Not (Test-Configuration -Key $Key)){ - return $null - } - - try{ - $ret = Get-Content $path | ConvertFrom-Json -AsHashtable -ErrorAction Stop - return $ret - } - catch{ - Write-Warning "Error reading configuration ($Key) file: $($path). $($_.Exception.Message)" - return $null - } -} - -function Save-Configuration { - [CmdletBinding()] - param( - [Parameter(Position = 0)][string]$Key = "config", - [Parameter(Mandatory = $true, Position = 1)][Object]$Config - ) - - $path = GetConfigFile -Key $Key - - try { - $Config | ConvertTo-Json -Depth 10 | Set-Content $path -ErrorAction Stop - } - catch { - Write-Warning "Error saving configuration ($Key) to file: $($path). $($_.Exception.Message)" - return $false - } - - return $true -} - - - - - - - - - - diff --git a/include/databaseV2.ps1 b/include/databaseV2.ps1 index 3c9b48a..4fa8d1c 100644 --- a/include/databaseV2.ps1 +++ b/include/databaseV2.ps1 @@ -70,8 +70,8 @@ if(-not (Test-Path -Path function:"Reset-$DB_INVOKE_GET_ROOT_PATH_ALIAS")){ New-Item -Path $databaseRoot -ItemType Directory } - Rename-Item -path Function:Reset-MyModuleDatabaseStore -NewName "Reset-$DB_INVOKE_GET_ROOT_PATH_ALIAS" - Export-ModuleMember -Function "Reset-$DB_INVOKE_GET_ROOT_PATH_ALIAS" + Rename-Item -path Function:Reset-MyModuleDatabaseStore -NewName "Reset-$($moduleName)DatabaseStore" + Export-ModuleMember -Function "Reset-$($moduleName)DatabaseStore" } # PRIVATE FUNCTIONS @@ -156,5 +156,4 @@ function Test-DatabaseKey{ # TODO: Return $false if cache has expired return $true -} - +} \ No newline at end of file diff --git a/private/samplePrivateFunction.ps1 b/private/samplePrivateFunction.ps1 deleted file mode 100644 index f929475..0000000 --- a/private/samplePrivateFunction.ps1 +++ /dev/null @@ -1,8 +0,0 @@ - -function Get-PrivateString { - param ( - [Parameter()][string]$Param1 - ) - - return ("Private string [{0}]" -f $param1) -} diff --git a/public/CsvDatabase.ps1 b/public/CsvDatabase.ps1 new file mode 100644 index 0000000..508881b --- /dev/null +++ b/public/CsvDatabase.ps1 @@ -0,0 +1,95 @@ +<# +.SYNOPSIS + This function retrieves the key for a CSV file used to create the database JSON file name. +.DESCRIPTION + This function retrieves the key for a CSV file used to create the database JSON file name. + The key is generated based on the path of the CSV file, the specified key column, and the last modified time of the file. +.PARAMETER Path + The path to the CSV file. +.PARAMETER KeyColumn + The column to use as the key for the database. +.EXAMPLE + $key = Get-CsvDatabaseKey -Path "C:\path\to\file.csv" -KeyColumn "Column1" + This command retrieves the key for the specified CSV file using "Column1" as the key column. +.EXAMPLE +#> +function Get-CsvDatabaseKey { + [CmdletBinding()] + param ( + + [Parameter(Mandatory=$true, + Position=0, + ParameterSetName="ParameterSetName", + ValueFromPipeline=$true, + ValueFromPipelineByPropertyName=$true, + HelpMessage="Path to one or more locations.")] + [Alias("PSPath")] + [ValidateNotNullOrEmpty()] + [string[]] + $Path, + [Parameter(Mandatory)][string]$KeyColumn + ) + + process { + + $paths = Get-ChildItem -Path $Path + + foreach ($path in $paths) { + + if (-not (Test-Path -Path $Path)) { + throw "The specified path does not exist: $Path" + } + + $item = Get-Item -Path $Path + + $lastmodified = $item.LastWriteTime + + $lastmodified = $lastmodified.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ") + + $path = $item | Convert-Path + + $key = "$path - $KeyColumn - $lastmodified" + + $ret = $key | Get-HashCode + + return $ret + } + } +} Export-ModuleMember -Function Get-CsvDatabaseKey + +function Save-CsvDatabase{ + [CmdletBinding()] + param ( + [Parameter(Mandatory, Position = 0)] [string]$Key, + [Parameter(Mandatory, Position = 1)] [object]$Data, + [Parameter(Mandatory, Position = 2)] [string]$KeyColumn + ) + + $CsvDatabase = New-Object System.Collections.Hashtable + + foreach ($row in $Data) { + $keyValue = $row.$KeyColumn + + if (-not $CsvDatabase.ContainsKey($keyValue)) { + $CsvDatabase[$keyValue] = @{} + } + + foreach ($property in $row.PSObject.Properties) { + $CsvDatabase[$keyValue][$property.Name] = $property.Value + } + } + + Save-DatabaseKey -Key $key -Value $CsvDatabase +} + +function Get-CsvDatabase{ + [CmdletBinding()] + param ( + [Parameter(Mandatory, Position = 0)] [string]$Key + ) + + $ret = Get-DatabaseKey -Key $key + + return $ret + +} \ No newline at end of file diff --git a/public/CsvFile.ps1 b/public/CsvFile.ps1 new file mode 100644 index 0000000..619f139 --- /dev/null +++ b/public/CsvFile.ps1 @@ -0,0 +1,48 @@ +<# +.SYNOPSIS + Module for handling CSV files with a database-like interface. +.DESCRIPTION + This module provides functions to import CSV files into a database-like structure, + allowing for easy access and manipulation of the data. + It includes functions to import CSV files, retrieve records by ID, and save the database. + The database is stored in JSON format for easy access and manipulation. +.EXAMPLE + $key = Import-CsvFile -Path "C:\path\to\file.csv" -KeyColumn "Column1" + This command imports a CSV file and uses the "Column1" column as the key for the database. + The key is returned for further use. +.EXAMPLE + $key = Import-CsvFile -Path "C:\path\to\file.csv" + This command imports a CSV file and uses the default "Id" column as the key for the database. + The key is returned for further use. +.Note + Use Invoke-CsvHelperGetDbRootPath to retreive the path where the database is stored. + Use Get-CsvRecord to retrieve records from the database. + Use Get-CsvDatabaseKey to retrieve the key for the csv file used to create the database JSON file name for that path. +#> +function Import-CsvFile { + param ( + [string]$Path, + [string]$KeyColumn = "Id" + ) + + if (-Not (Test-Path $Path)) { + Write-Error "File not found: $Path" + return + } + + try { + + $key = Get-CsvDatabaseKey -Path $Path -KeyColumn $KeyColumn + $data = Import-Csv -Path $Path + + Save-CsvDatabase -Key $key -Data $data -KeyColumn $KeyColumn + + return $key + + } catch { + Write-Error "Failed to load CSV file: $_" + } +} Export-ModuleMember -Function Import-CsvFile + + + diff --git a/public/CsvRecord.ps1 b/public/CsvRecord.ps1 new file mode 100644 index 0000000..35892b8 --- /dev/null +++ b/public/CsvRecord.ps1 @@ -0,0 +1,66 @@ + +<# +.SYNOPSIS + Get a record from a CSV file. +.DESCRIPTION + This function retrieves a record form a database seaded from a CSV file. + One of the columns of the CSV will be used as primary key. + This column is specified during Import-CsvFile. + By default the column is "Id". + If the database has not been imported yet, the function will import the CSV file. +.PARAMETER Path + The path to the CSV file. +.PARAMETER KeyColumn + The column to use as the key for the database. + Default is "Id". +.PARAMETER Key + The key for the database. + You can use this parameter in case you imported the CSV file in advance and captured the key. +.PARAMETER Id + The ID of the record to retrieve. + This is the value of the key column in the CSV file. This KeyColumn is specified during Import-CsvFile or using $KeyColumn parameter. +.EXAMPLE + +#> +function Get-CsvRecord{ + [CmdletBinding()] + param ( + [Parameter(Mandatory, ParameterSetName = "Path", Position = 0)] [string]$Path, + [Parameter(ParameterSetName = "Path", Position = 1)] [string]$KeyColumn = "Id", + [Parameter(Mandatory, ParameterSetName = "CsvKey", Position = 1)] [string]$Key, + [Parameter(Mandatory, Position = 3)] [string]$Id + ) + + # resolve CsvKey if not provided + if([string]::IsNullOrWhiteSpace($Key)){ + $Key = Get-CsvDatabaseKey -Path $Path -KeyColumn $KeyColumn + } + + # It DB not exist import csv file + if(-not $(Test-DatabaseKey -Key $Key) -and ($path | Test-Path )){ + $Key = Import-CsvFile -Path $Path -KeyColumn $KeyColumn + } + + # Get the database + $db = Get-CsvDatabase -Key $Key + + if (-Not $db) { + throw "Database not found for Key[$Key] Path[$Path]" + } + + $record = $db.$Id + + if (-Not $record) { + Write-Error "Record not found for ID: $Id in Csv $Path" + return + } + + $record = $db.$Id + + if (-Not $record) { + Write-Error "Record not found for ID: $Id in Csv $Path" + return + } + + return $record +} Export-ModuleMember -Function Get-CsvRecord \ No newline at end of file diff --git a/public/samplePublicFunction.ps1 b/public/samplePublicFunction.ps1 deleted file mode 100644 index ad678be..0000000 --- a/public/samplePublicFunction.ps1 +++ /dev/null @@ -1,8 +0,0 @@ - -function Get-PublicString { - param ( - [Parameter()][string]$Param1 - ) - - return ("Public string [{0}]" -f $param1) -} Export-ModuleMember -Function Get-PublicString