Functions/GenXdev.Data.SQLite/Invoke-SQLiteQuery.ps1
################################################################################ <# .SYNOPSIS Executes one or more SQL queries against a SQLite database with transaction support. .DESCRIPTION Executes SQL queries against a SQLite database with parameter support and configurable transaction isolation. All queries run in a single transaction that rolls back on error. Supports both connection strings and database file paths. .PARAMETER ConnectionString The SQLite connection string for database access. .PARAMETER DatabaseFilePath The file path to the SQLite database. Will be converted to a connection string. .PARAMETER Queries One or more SQL queries to execute. Can be passed via pipeline. .PARAMETER SqlParameters Optional parameters for the queries as hashtables. Format: @{"param"="value"} .PARAMETER IsolationLevel Transaction isolation level. Defaults to ReadCommitted. .EXAMPLE Invoke-SQLiteQuery -DatabaseFilePath "C:\data.db" -Queries "SELECT * FROM Users" .EXAMPLE "SELECT * FROM Users" | isql "C:\data.db" @{"UserId"=1} #> function Invoke-SQLiteQuery { [CmdletBinding(DefaultParameterSetName = "Default")] param ( ########################################################################### [Parameter( Position = 0, Mandatory, ParameterSetName = 'ConnectionString', HelpMessage = 'The connection string to the SQLite database.' )] [string]$ConnectionString, ########################################################################### [Parameter( Position = 0, Mandatory, ParameterSetName = 'DatabaseFilePath', HelpMessage = 'The path to the SQLite database file.' )] [string]$DatabaseFilePath, ########################################################################### [Alias("q", "Value", "Name", "Text", "Query")] [parameter( Mandatory, Position = 1, ValueFromRemainingArguments, ValueFromPipeline, ValueFromPipelineByPropertyName, HelpMessage = 'The query or queries to execute.' )] [string[]]$Queries, ########################################################################### [Alias("data", "parameters", "args")] [parameter( Position = 1, ValueFromRemainingArguments, ValueFromPipeline, ValueFromPipelineByPropertyName, HelpMessage = 'Query parameters as hashtables.' )] [System.Collections.Hashtable[]]$SqlParameters = @(), ########################################################################### [Parameter( Mandatory = $false, HelpMessage = 'Transaction isolation level.' )] [System.Data.IsolationLevel]$IsolationLevel = [System.Data.IsolationLevel]::ReadCommitted ) begin { # initialize connection string from file path if provided $connString = [String]::IsNullOrWhiteSpace($DatabaseFilePath) ` ? $ConnectionString ` : "Data Source=$((Expand-Path $DatabaseFilePath))" Write-Verbose "Opening SQLite connection..." } process { try { # establish database connection $connection = New-Object System.Data.SQLite.SQLiteConnection($connString) $connection.Open() # begin transaction with specified isolation $transaction = $connection.BeginTransaction($IsolationLevel) Write-Verbose "Started transaction with $IsolationLevel isolation" # ensure parameters array exists $SqlParameters = if ($SqlParameters) { $SqlParameters } else { @() } try { $idx = -1 # process each query $Queries | ForEach-Object { $idx++ Write-Verbose "Executing query $($idx + 1) of $($Queries.Count)" # get parameter set for current query $data = if ($SqlParameters.Length -gt 0) { $SqlParameters[[Math]::Min($idx, $SqlParameters.Count - 1)] } else { $null } # prepare command $command = $connection.CreateCommand() $command.CommandText = $PSItem # add parameters if provided if ($null -ne $data) { $data.GetEnumerator() | ForEach-Object { $null = $command.Parameters.AddWithValue( "@" + $PSItem.Key, $PSItem.Value ) } } # execute and read results $reader = $command.ExecuteReader() while ($reader.Read()) { $record = @{} for ($i = 0; $i -lt $reader.FieldCount; $i++) { $record[$reader.GetName($i)] = $reader.GetValue($i) } Write-Output $record } } # commit if successful $transaction.Commit() Write-Verbose "Transaction committed successfully" } catch { # rollback on error $transaction.Rollback() Write-Verbose "Transaction rolled back due to error" throw $_ } finally { if ($null -ne $reader) { $reader.Close() } $connection.Close() Write-Verbose "Connection closed" } } catch { throw $_ } } end { } } ################################################################################ |