From ce9698c7a5024fe5a259ee179c9a85d09ee1bc5e Mon Sep 17 00:00:00 2001 From: Roger Pack Date: Wed, 6 Apr 2022 16:38:55 -0600 Subject: [PATCH 1/2] Update DB Readme Add example of query parameters in a query, mention there are more helper methods available for query, mention preparedstatements are at play crystal-db/#164 --- docs/database/README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/docs/database/README.md b/docs/database/README.md index f4d555590..b8249ab09 100644 --- a/docs/database/README.md +++ b/docs/database/README.md @@ -76,6 +76,8 @@ db.exec "insert into contacts values (?, ?)", "John", 30 # Postgres db.exec "insert into contacts values ($1, $2)", "Sarah", 33 ``` +Query parameters are accomplished typically using PreparedStatements under the hood, +though this can be disabled via a connection string option `prepared_statements=false`. ## Query @@ -91,6 +93,16 @@ db.query "select name, age from contacts order by age desc" do |rs| end ``` +You can also use query parameters: + +```crystal +db.query("select name from contacts where age = ?", 33) do |rs| + rs.each do + # ... perform for each row in the ResultSet + end +end +``` + When reading values from the database there is no type information during compile time that crystal can use. You will need to call `rs.read(T)` with the type `T` you expect to get from the database. ```crystal @@ -105,7 +117,7 @@ db.query "select name, age from contacts order by age desc" do |rs| end ``` -There are many convenient query methods built on top of `#query`. +There are many convenient query methods built on top of `#query` to make this easier. You can read multiple columns at once: @@ -125,4 +137,5 @@ Or read a scalar value without dealing explicitly with the ResultSet: max_age = db.scalar "select max(age) from contacts" ``` +There are many other helper methods to query with types, query column names with types, etc. All available methods to perform statements in a database are defined in `DB::QueryMethods`. From a14719597b76886b4fa3f8a004c8fef77e346bbd Mon Sep 17 00:00:00 2001 From: rogerdpack Date: Thu, 7 Apr 2022 18:43:40 -0600 Subject: [PATCH 2/2] Move the explanation of query parameters to a separate section and reference that --- docs/database/README.md | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/docs/database/README.md b/docs/database/README.md index b8249ab09..e718eb46b 100644 --- a/docs/database/README.md +++ b/docs/database/README.md @@ -67,21 +67,15 @@ To execute sql statements you can use `Database#exec` db.exec "create table contacts (name varchar(30), age int)" ``` -To avoid [SQL injection](https://owasp.org/www-community/attacks/SQL_Injection) values can be provided as query parameters. -The syntax for using query parameters depends on the database driver because they are typically just passed through to the database. MySQL uses `?` for parameter expansion and assignment is based on argument order. PostgreSQL uses `$n` where `n` is the ordinal number of the argument (starting with 1). - ```crystal -# MySQL -db.exec "insert into contacts values (?, ?)", "John", 30 -# Postgres -db.exec "insert into contacts values ($1, $2)", "Sarah", 33 +db.exec "insert into contacts (name, age) values ('abc', 30)" ``` -Query parameters are accomplished typically using PreparedStatements under the hood, -though this can be disabled via a connection string option `prepared_statements=false`. + +Values can be provided as query parameters, see below. ## Query -To perform a query and get the result set use `Database#query`, arguments can be used as in `Database#exec`. +To perform a query and get the result set use `Database#query`. `Database#query` returns a `ResultSet` that needs to be closed. As in `Database#open`, if called with a block, the `ResultSet` will be closed implicitly. @@ -93,9 +87,19 @@ db.query "select name, age from contacts order by age desc" do |rs| end ``` -You can also use query parameters: +Values can be provided as query parameters, see below. + +## Query Parameters + +To avoid [SQL injection](https://owasp.org/www-community/attacks/SQL_Injection) values can be provided as query parameters. +The syntax for using query parameters depends on the database driver because they are typically just passed through to the database. MySQL uses `?` for parameter expansion and assignment is based on argument order. PostgreSQL uses `$n` where `n` is the ordinal number of the argument (starting with 1). ```crystal +# MySQL +db.exec "insert into contacts values (?, ?)", "John", 30 +# Postgres +db.exec "insert into contacts values ($1, $2)", "Sarah", 33 +# Queries: db.query("select name from contacts where age = ?", 33) do |rs| rs.each do # ... perform for each row in the ResultSet @@ -103,6 +107,8 @@ db.query("select name from contacts where age = ?", 33) do |rs| end ``` +## Reading Query Results + When reading values from the database there is no type information during compile time that crystal can use. You will need to call `rs.read(T)` with the type `T` you expect to get from the database. ```crystal