Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for application_name #274

Merged
merged 1 commit into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ spec/.run_auth_specs
.cert
.envrc
result
.direnv
9 changes: 9 additions & 0 deletions spec/pg/connection_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ describe PG::Connection, "#initialize" do
DB.open("postgres://localhost:5433")
}
end

it "set application name" do
URI.parse(DB_URL).tap do |uri|
uri.query = "application_name=specs"
DB.open(uri.to_s) do |db|
db.query_one("SHOW application_name", as: String).should eq("specs")
end
end
end
end

describe PG::Connection, "#on_notice" do
Expand Down
12 changes: 8 additions & 4 deletions spec/pq/conninfo_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ private def assert_default_params(ci)
ci.password.should eq(nil)
ci.port.should eq(5432)
ci.sslmode.should eq(:prefer)
ci.application_name.should eq("crystal")
end

private def assert_custom_params(ci)
Expand All @@ -18,6 +19,7 @@ private def assert_custom_params(ci)
ci.password.should eq("pass")
ci.port.should eq(5555)
ci.sslmode.should eq(:require)
ci.application_name.should eq("specs")
end

private def assert_ssl_params(ci)
Expand All @@ -36,7 +38,7 @@ describe PQ::ConnInfo, "parts" do
end

it "can take settings" do
ci = PQ::ConnInfo.new("host", "db", "user", "pass", 5555, :require)
ci = PQ::ConnInfo.new("host", "db", "user", "pass", 5555, :require, "specs")
assert_custom_params ci
end
end
Expand All @@ -51,15 +53,15 @@ describe PQ::ConnInfo, ".from_conninfo_string" do

it "parses postgres urls" do
ci = PQ::ConnInfo.from_conninfo_string(
"postgres://user:pass@host:5555/db?sslmode=require&otherparam=ignore")
"postgres://user:pass@host:5555/db?sslmode=require&otherparam=ignore&application_name=specs")
assert_custom_params ci

ci = PQ::ConnInfo.from_conninfo_string(
"postgres://user:pass@host:5555/db?sslmode=verify-full&sslcert=postgresql.crt&sslkey=postgresql.key&sslrootcert=root.crt")
assert_ssl_params ci

ci = PQ::ConnInfo.from_conninfo_string(
"postgresql://user:pass@host:5555/db?sslmode=require")
"postgresql://user:pass@host:5555/db?sslmode=require&application_name=specs")
assert_custom_params ci
end

Expand All @@ -72,7 +74,7 @@ describe PQ::ConnInfo, ".from_conninfo_string" do

it "parses libpq style strings" do
ci = PQ::ConnInfo.from_conninfo_string(
"host=host dbname=db user=user password=pass port=5555 sslmode=require")
"host=host dbname=db user=user password=pass port=5555 sslmode=require application_name=specs")
assert_custom_params ci

ci = PQ::ConnInfo.from_conninfo_string(
Expand Down Expand Up @@ -125,12 +127,14 @@ describe PQ::ConnInfo, ".from_conninfo_string" do
ENV["PGPASSWORD"] = "C"
ENV["PGPORT"] = "1"
ENV["PGUSER"] = "D"
ENV["PGAPPNAME"] = "S"
ci = PQ::ConnInfo.from_conninfo_string("postgres://")
ci.database.should eq("A")
ci.host.should eq("B")
ci.password.should eq("C")
ci.port.should eq(1)
ci.user.should eq("D")
ci.application_name.should eq("S")
end

env_var_bubble do
Expand Down
2 changes: 1 addition & 1 deletion src/pq/connection.cr
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ module PQ
startup_args = [
"user", @conninfo.user,
"database", @conninfo.database,
"application_name", "crystal",
"application_name", @conninfo.application_name,
"client_encoding", "utf8",
]

Expand Down
20 changes: 15 additions & 5 deletions src/pq/conninfo.cr
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,21 @@ module PQ
# The sslrootcert. Optional.
getter sslrootcert : String?

# The application name. Optional (defaults to "crystal").
getter application_name : String

getter auth_methods : Array(String) = %w[scram-sha-256-plus scram-sha-256 md5]

# Create a new ConnInfo from all parts
def initialize(host : String? = nil, database : String? = nil, user : String? = nil, password : String? = nil, port : Int | String? = nil, sslmode : String | Symbol? = nil)
def initialize(host : String? = nil, database : String? = nil, user : String? = nil, password : String? = nil, port : Int | String? = nil, sslmode : String | Symbol? = nil, application_name : String? = nil)
@host = default_host host
db = default_database database
@database = db.lchop('/')
@user = default_user user
@port = (port || ENV.fetch("PGPORT", "5432")).to_i
@sslmode = default_sslmode sslmode
@password = password || ENV.fetch("PGPASSWORD", PgPass.locate(@host, @port, @database, @user))
@application_name = default_application_name application_name
end

# Initialize with either "postgres://" urls or postgres "key=value" pairs
Expand All @@ -71,8 +75,9 @@ module PQ

# Initializes with a `URI`
def initialize(uri : URI)
hostname = uri.hostname.presence || URI::Params.parse(uri.query.to_s).fetch("host", "")
initialize(hostname, uri.path, uri.user, uri.password, uri.port, :prefer)
params = URI::Params.parse(uri.query.to_s)
hostname = uri.hostname.presence || params.fetch("host", "")
initialize(hostname, uri.path, uri.user, uri.password, uri.port, :prefer, params.fetch("application_name", nil))
if q = uri.query
HTTP::Params.parse(q) do |key, value|
handle_sslparam(key, value)
Expand All @@ -83,10 +88,11 @@ module PQ
# Initialize with a `Hash`
#
# Valid keys match Postgres "conninfo" keys and are `"host"`, `"dbname"`,
# `"user"`, `"password"`, `"port"`, `"sslmode"`, `"sslcert"`, `"sslkey"` and `"sslrootcert"`
# `"user"`, `"password"`, `"port"`, `"sslmode"`, `"sslcert"`, `"sslkey"`,
# `"sslrootcert"` and `"application_name"`.
def initialize(params : Hash)
initialize(params["host"]?, params["dbname"]?, params["user"]?,
params["password"]?, params["port"]?, params["sslmode"]?)
params["password"]?, params["port"]?, params["sslmode"]?, params["application_name"]?)
params.each do |key, value|
handle_sslparam(key, value)
end
Expand Down Expand Up @@ -137,6 +143,10 @@ module PQ
end
end

private def default_application_name(application_name, fallback_application_name = "crystal")
application_name || ENV.fetch("PGAPPNAME", nil) || fallback_application_name
end

private def default_user(u)
u || ENV.fetch("PGUSER", current_user_name)
end
Expand Down