214 lines
7.0 KiB
Julia
214 lines
7.0 KiB
Julia
module dbUtil
|
||
|
||
export dictToPostgresKeyValueString, generateInsertSQL, generateUpdateSQL
|
||
|
||
using JSON, DataStructures, Distributions, Random, Dates, UUIDs, DataFrames,
|
||
SHA
|
||
using ..util
|
||
#[PENDING] update code to use JSON
|
||
# ---------------------------------------------- 100 --------------------------------------------- #
|
||
|
||
|
||
"""
|
||
dictToPostgresKeyValueString - Convert dictionary to PostgreSQL key-value string format
|
||
|
||
This function takes a dictionary and converts it into a PostgreSQL-compatible key-value string
|
||
format suitable for storage in a TEXT field. The output format uses curly braces with comma-separated
|
||
key-value pairs, where string values are quoted.
|
||
|
||
# Function Workflow:
|
||
1. Iterates through dictionary key-value pairs
|
||
2. Handles nested dictionaries by recursively converting them
|
||
3. Wraps string values in double quotes
|
||
4. Formats numeric and other values without quotes
|
||
5. Returns a PostgreSQL-compatible key-value string enclosed in curly braces
|
||
|
||
# Arguments:
|
||
- `dict::Dict` - Dictionary containing key-value pairs to convert
|
||
|
||
# Return:
|
||
- A String in PostgreSQL key-value format: "{key1: value1, key2: \"value2\", ...}"
|
||
|
||
# Example
|
||
```jldoctest
|
||
julia> data = Dict{String, Any}(
|
||
"name" => "John",
|
||
"age" => 30,
|
||
"city" => "New York"
|
||
);
|
||
|
||
julia> dictToPostgresKeyValueString(data)
|
||
"{\"name\": \"John\", \"age\": 30, \"city\": \"New York\"}"
|
||
```
|
||
"""
|
||
function dictToPostgresKeyValueString(dict)
|
||
parts = []
|
||
for (k, v) in dict
|
||
if isa(v, Dict)
|
||
push!(parts, "\"$k\": " * dict_to_string(v))
|
||
elseif isa(v, AbstractString)
|
||
push!(parts, "\"$k\": \"$v\"")
|
||
else
|
||
push!(parts, "\"$k\": $v")
|
||
end
|
||
end
|
||
return "{" * join(parts, ", ") * "}"
|
||
end
|
||
|
||
|
||
|
||
|
||
""" generateInsertSQL - Generate SQL INSERT statement from dictionary data
|
||
|
||
This function constructs a SQL INSERT statement by extracting values for specified columns
|
||
from a dictionary and formatting them into a valid PostgreSQL INSERT query.
|
||
|
||
# Function Workflow:
|
||
1. Iterates through the dictionary key-value pairs
|
||
2. Filters keys to only include those present in `columnToInsert`
|
||
3. Collects column names and their corresponding values
|
||
4. Constructs the final SQL INSERT statement
|
||
|
||
# Arguments:
|
||
- `table_name::String` - Name of the database table to insert into
|
||
- `columnToInsert::Vector{Symbol}` - List of column names to include in the INSERT statement
|
||
- `data::Dict{Symbol, Any}` - Dictionary containing column-value pairs for the insert
|
||
|
||
# Return:
|
||
- A String containing the SQL INSERT statement
|
||
|
||
# Example
|
||
```jldoctest
|
||
julia> using UUIDs
|
||
|
||
# Insert a single record with specific columns
|
||
table_name = "wine"
|
||
columnToInsert = [:acidity, :tannin, :country, :region, :winery]
|
||
data = Dict{Symbol, Any}(
|
||
:grape => "Cabernet Sauvignon",
|
||
:acidity => "medium", # using descriptive scale (low/medium/full)
|
||
:tannin => "medium-plus", # common wine descriptor
|
||
:country => "France",
|
||
:description => "A rich and structured red wine with notes of blackcurrant, cedar, and subtle oak.",
|
||
:region => "Bordeaux",
|
||
:winery => "Château Margaux",
|
||
:intensity => "medium", # intensity is usually low/medium/full
|
||
:sweetness => "dry", # dry/medium-dry/medium/medium-sweet/sweet
|
||
:tasting_notes => "Blackberry, graphite, tobacco, vanilla, and subtle earth.",
|
||
:wine_name => "Château Margaux Grand Cru",
|
||
:wine_id => "8f3c7a2e-1b4d-4a9f-9c2e-4a8b3d6e5f7a", # UUID-like (valid hex)
|
||
:wine_type => "Red",
|
||
:other_attributes => Dict{String, Any}(
|
||
"vintage" => 2018,
|
||
"alcohol_percent" => 13.5,
|
||
"ph" => 3.6,
|
||
" aging_years" => 24, # years in barrel
|
||
" producer_code" => "CM-GRAND"
|
||
),
|
||
:fizziness => "still",
|
||
:serving_temperature => "16–18°C",
|
||
:additional_search_term => ["Cabernet", "Bordeaux red", "premium wine", "CabSav"]
|
||
)
|
||
|
||
julia> generateInsertSQL(table_name, columnToInsert, data)
|
||
"INSERT INTO wine (acidity, tannin, country, region, winery) VALUES ('medium', 'medium-plus', 'France', 'Bordeaux', 'Château Margaux');"
|
||
```
|
||
"""
|
||
function generateInsertSQL(table_name::String, columnToInsert::Vector{Symbol}, data::Dict{Symbol, Any})
|
||
columns = String[]
|
||
values = String[]
|
||
|
||
for (key, value) in data
|
||
if key ∈ columnToInsert
|
||
push!(columns, string(key))
|
||
push!(values, "'$value'") #[] number should not wrapped in ''
|
||
end
|
||
end
|
||
|
||
columns_str = join(columns, ", ")
|
||
values_str = join(values, ", ")
|
||
|
||
return "INSERT INTO $table_name ($columns_str) VALUES ($values_str);"
|
||
end
|
||
|
||
|
||
# ---------------------------------------------- 100 --------------------------------------------- #
|
||
|
||
""" generateUpdateSQL - Generate SQL UPDATE statement from dictionary data
|
||
|
||
This function constructs a SQL UPDATE statement by updating multiple columns
|
||
based on a primary key condition.
|
||
|
||
# Arguments:
|
||
- `table_name::String` - Name of the database table to update
|
||
- `pk_column::Symbol` - The primary key column name
|
||
- `pk_value` - The primary key value (used in WHERE clause)
|
||
- `data::Dict{Symbol, Any}` - Dictionary containing column-value pairs to update
|
||
|
||
# Return:
|
||
- A String containing the SQL UPDATE statement
|
||
|
||
# Example
|
||
```jldoctest
|
||
julia> using UUIDs
|
||
|
||
# Update multiple columns using a dictionary
|
||
table_name = "wine"
|
||
pk_column = :wine_id
|
||
pk_value = "8f3c7a2e-1b4d-4a9f-9c2e-4a8b3d6e5f7a"
|
||
data = Dict{Symbol, Any}(
|
||
:acidity => "full",
|
||
:tannin => "medium",
|
||
:country => "Italy"
|
||
)
|
||
|
||
julia> generateUpdateSQL(table_name, pk_column, pk_value, data)
|
||
"UPDATE wine SET acidity = 'full', tannin = 'medium', country = 'Italy' WHERE wine_id = '8f3c7a2e-1b4d-4a9f-9c2e-4a8b3d6e5f7a';"
|
||
```
|
||
"""
|
||
function generateUpdateSQL(table_name::String, pk_column::String, pk_value,
|
||
data::AbstractDict{String, Any})
|
||
# Build SET clause
|
||
set_parts = String[]
|
||
for (key, value) in data
|
||
if key ∉ [pk_column]
|
||
value_str = isa(value, AbstractString) ? "'$value'" : "$value"
|
||
push!(set_parts, "$(string(key)) = $value_str")
|
||
end
|
||
end
|
||
|
||
set_clause = join(set_parts, ", ")
|
||
|
||
# Handle primary key value
|
||
pk_val_str = isa(pk_value, AbstractString) ? "'$pk_value'" : "$pk_value"
|
||
|
||
return "UPDATE $table_name SET $set_clause WHERE $pk_column = $pk_val_str;"
|
||
end
|
||
|
||
function generateUpdateSQL(table_name::String, pk_dict::AbstractDict{String, Any},
|
||
data::AbstractDict{String, Any})
|
||
# Build SET clause
|
||
set_parts = String[]
|
||
for (key, value) in data
|
||
if key ∉ pk_columns
|
||
value_str = isa(value, AbstractString) ? "'$value'" : "$value"
|
||
push!(set_parts, "$(string(key)) = $value_str")
|
||
end
|
||
end
|
||
|
||
set_clause = join(set_parts, ", ")
|
||
|
||
# Build WHERE clause for composite keys
|
||
where_parts = String[]
|
||
for (col, val) in pk_dict
|
||
val_str = isa(val, AbstractString) ? "'$val'" : "$val"
|
||
push!(where_parts, "$(string(col)) = $val_str")
|
||
end
|
||
|
||
where_clause = join(where_parts, " AND ")
|
||
|
||
return "UPDATE $table_name SET $set_clause WHERE $where_clause;"
|
||
end
|
||
|
||
|
||
end # module |