-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Jeremiah
committed
Apr 30, 2024
1 parent
f24dbdc
commit 532e722
Showing
3 changed files
with
575 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
@{ | ||
# ID used to uniquely identify this module | ||
GUID = 'd625bfc7-f852-408c-b254-1e5475804539' | ||
|
||
# Author of this module | ||
Author = 'Jeremiah Haywood' | ||
|
||
# Copyright statement for this module | ||
Copyright = '(c) 2024 Jeremiah Haywood. All rights reserved.' | ||
|
||
# Version number of this module. | ||
ModuleVersion = '1.0' | ||
|
||
# Minimum version of PowerShell this module requires | ||
PowerShellVersion = '7.4' | ||
|
||
# Script files (.ps1) that are run in the caller's environment prior to importing this module. | ||
ScriptsToProcess = @( | ||
'.\classes\DbHandler' | ||
) | ||
|
||
# required for working with sqlite | ||
RequiredAssemblies = $( | ||
if ($env:OS -ne 'Windows_NT') { | ||
@( | ||
".\lib\linux\System.Data.SQLite.dll" | ||
) | ||
} else { | ||
@( | ||
".\lib\win\System.Data.SQLite.dll" | ||
) | ||
} | ||
) | ||
|
||
# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. | ||
PrivateData = @{ | ||
PSData = @{ | ||
# Tags applied to this module. These help with module discovery in online galleries. | ||
Tags = @('Database','Odbc','Postgres','SQLite') | ||
|
||
# A URL to the license for this module. | ||
LicenseUri = 'https://github.com/port-43/DbHandler/blob/main/LICENSE' | ||
|
||
# A URL to the main website for this project. | ||
ProjectUri = 'https://github.com/port-43/DbHandler' | ||
|
||
# A URL to an icon representing this module. | ||
# IconUri = '' | ||
|
||
# ReleaseNotes of this module | ||
# ReleaseNotes = '' | ||
|
||
# Prerelease string of this module | ||
# Prerelease = '' | ||
|
||
# Flag to indicate whether the module requires explicit user acceptance for install/update/save | ||
RequireLicenseAcceptance = $true | ||
|
||
# External dependent modules of this module | ||
# ExternalModuleDependencies = @() | ||
|
||
} # End of PSData hashtable | ||
} # End of PrivateData hashtable | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
# DbHandler | ||
This module provides a class to work with databases using Odbc/SQLite .NET framework. | ||
|
||
# Using the module | ||
## Working with SQLite | ||
The most basic constructor creates a DbHandler that works with sqlite. It accepts a full path to the sqlite database. Under the hood the class is implementing `System.Data.SqlLite`. The dll required is included in the packaged release of this module. | ||
```powershell | ||
# creating DbHandler object for SQLite connection | ||
$Handler = [DbHandler]::new("C:\Path\to\sqlite.db") | ||
``` | ||
|
||
## Working with Postgres/Odbc | ||
To create a DbHandler to work with the Odbc .NET framework provide the following parameters in this order: | ||
- Server hostname/ip address | ||
- Database name | ||
- Port | ||
- Driver | ||
- Credential | ||
|
||
```powershell | ||
# creating DbHandler object for Odbc connection | ||
$Credential = Get-Credential -UserName 'username' | ||
$Handler = [DbHandler]::new('192.168.20.103', 'test_database', '5432', 'PostgreSQL UNICODE(x64)', $Credential) | ||
``` | ||
|
||
## Querying data | ||
```powershell | ||
# simple query | ||
$Statement = "SELECT * FROM test_table" | ||
$Handler.GetDatabaseData($Statement) | ||
# using parameters | ||
$Statement = "SELECT * FROM test_table WHERE name = @name" | ||
$Param = [ordered]@{name = "test"} | ||
$Handler.GetDatabaseData($Statement, $Param) | ||
``` | ||
## Setting data | ||
```powershell | ||
# simple statement | ||
$Statement = "CREATE TABLE test_table (name varchar, fname varchar, lname varchar);" | ||
$Handler.SetDatabaseData($Statement) | ||
# using parameters | ||
$Statement = "INSERT INTO test_table (name, fname, lname) VALUES (@name, @first, @last)" | ||
$Param = [ordered]@{name = "test"; first = "first"; last = "last"} | ||
$Handler.SetDatabaseDataTransaction($Statement, $Param) | ||
# using transactions | ||
$Statement = "INSERT INTO test_table (name, fname, lname) VALUES (@name, @first, @last)" | ||
$Param = [ordered]@{name = "test"; first = "first"; last = "last"} | ||
$Handler.SetDatabaseDataTransaction($Statement, $Param) | ||
``` | ||
|
||
## Logging/Debugging | ||
The module also provides a built in logging that logs to stdout. To turn on logging set the `Debug` property value to true. | ||
```powershell | ||
# setting debug | ||
$Handler.Debug = $true | ||
``` | ||
There are two types of log formats supported, json and logfmt (json is the default). These can be managed via the `LogType` property. | ||
```powershell | ||
# setting log type | ||
$Handler.LogType = 'logfmt' | ||
$Handler.LogType = 'json' | ||
``` | ||
Example log output: | ||
``` | ||
# json | ||
{"timestamp":"2024-04-30 12:04:00.383","level":"info","thread":25,"hostname":"C-3PO","method":"GetDatabaseData ([string] $Statement, [OrderedDictionary] $Parameters)","message":"Opening db connection"} | ||
{"timestamp":"2024-04-30 12:04:00.396","level":"info","thread":25,"hostname":"C-3PO","method":"GetDatabaseData ([string] $Statement, [OrderedDictionary] $Parameters)","message":"Submitting query - SELECT * FROM test_table WHERE name = @name"} | ||
{"timestamp":"2024-04-30 12:04:00.398","level":"info","thread":25,"hostname":"C-3PO","method":"GetDatabaseData ([string] $Statement, [OrderedDictionary] $Parameters)","message":"Parameters - name=test"} | ||
{"timestamp":"2024-04-30 12:04:00.405","level":"info","thread":25,"hostname":"C-3PO","method":"GetDatabaseData ([string] $Statement, [OrderedDictionary] $Parameters)","message":"Closing db connection"} | ||
# logfmt | ||
timestamp="2024-04-30 12:09:05.406" level=info thread=25 hostname=C-3PO method="GetDatabaseData ([string] $Statement, [OrderedDictionary] $Parameters)" message="Opening db connection" | ||
timestamp="2024-04-30 12:09:05.407" level=info thread=25 hostname=C-3PO method="GetDatabaseData ([string] $Statement, [OrderedDictionary] $Parameters)" message="Submitting query - SELECT * FROM test_table WHERE name = @name" | ||
timestamp="2024-04-30 12:09:05.408" level=info thread=25 hostname=C-3PO method="GetDatabaseData ([string] $Statement, [OrderedDictionary] $Parameters)" message="Parameters - name=test" | ||
timestamp="2024-04-30 12:09:05.408" level=info thread=25 hostname=C-3PO method="GetDatabaseData ([string] $Statement, [OrderedDictionary] $Parameters)" message="Closing db connection | ||
``` | ||
|
||
## Considerations | ||
### Parameters | ||
As seen in the above examples the module supports providing parameters to the SQL statements to protect against SQL injection. However, not all Odbc drivers support named parameters but accept postional parameters instead (e.g. Postgres driver). In order to use positional parameters the code looks like the following: | ||
```powershell | ||
# positional parameter example | ||
$Statement = 'SELECT * FROM test_table WHERE name = ? and last = ?' | ||
$Param = [ordered]@{name = "test"; lname = "last"} | ||
$Handler.GetDatabaseData($Statement, $Param) | ||
``` | ||
Of note, the key names `name` and `lname` do not matter, only the order in which they're defined impacts how they're used in the sql statement. The following would work the exact same: | ||
```powershell | ||
# positional parameter example | ||
$Statement = 'SELECT * FROM test_table WHERE name = ? and last = ?' | ||
$Param = [ordered]@{asdf = "test"; qwer = "last"} | ||
$Handler.GetDatabaseData($Statement, $Param) | ||
``` | ||
### Connection Pooling | ||
Connection pooling is handled by the driver with the .NET odbc framework automatically. Documentation defines that if the connection string is the exact same it will use the same connection pool. | ||
|
||
### Multithreading | ||
The class implements the [NoRunspaceAffinity](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_classes?view=powershell-7.4#norunspaceaffinity-attribute]) attribute which ensures that the class isn't affiliated with a particular runspace. This allows for using the class in scenarios such as the following: | ||
```powershell | ||
$Handler = [DbHandler]::new("C:\Projects\sqlite\test.db") | ||
$Statement = "SELECT * FROM test_table WHERE name = @name" | ||
1..5 | Foreach-Object -ThrottleLimit 5 -Parallel { | ||
$DbHandler = $using:Handler | ||
$DbStatement = $using:Statement | ||
$Param = [ordered]@{name = "test$_"} | ||
$DbHandler.GetDatabaseData($DbStatement, $Param) | ||
} | ||
``` | ||
|
||
If you want logging to to still work in a multithreaded environment you will need to explicitiy set `$InformationPreference = 'continue'` before. |
Oops, something went wrong.