Skip to content

Commit

Permalink
#130 - Add #to_sql query set method
Browse files Browse the repository at this point in the history
  • Loading branch information
ellmetha committed May 11, 2024
1 parent eb08ced commit b69d7e2
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 1 deletion.
19 changes: 19 additions & 0 deletions docs/docs/models-and-databases/reference/query-set.md
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,25 @@ Order.all.sum(:amount) # Calculates the total amount across all orders
# => 7
```

### `to_s`

Returns a string representation of the considered query set.

### `to_sql`

Returns the SQL representation of the considered query set.

For example:

```crystal
Tag.filter(name__startswith: "r").to_sql
# => "SELECT app_tag.id, app_tag.name, app_tag.is_active FROM \"app_tag\" WHERE app_tag.name LIKE $1"
```

:::note
The outputted SQL will vary depending on the database backend in use.
:::

### `update`

Updates all the records matched by the current query set with the passed values.
Expand Down
14 changes: 14 additions & 0 deletions spec/marten/db/connection/base_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,20 @@ describe Marten::DB::Connection::Base do

sql.should eq "SELECT * FROM my_table WHERE id = 1"
end

it "rejects empty strings" do
conn = Marten::DB::Connection::SQLite.new(Marten::Conf::GlobalSettings::Database.new("default"))

sql = conn.build_sql do |s|
s << "SELECT *"
s << ""
s << "FROM my_table"
s << ""
s << "WHERE id = 1"
end

sql.should eq "SELECT * FROM my_table WHERE id = 1"
end
end

describe "#id" do
Expand Down
8 changes: 8 additions & 0 deletions spec/marten/db/query/set_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2709,6 +2709,14 @@ describe Marten::DB::Query::Set do
end
end

describe "#to_sql" do
it "produces the output of the query SQL representation" do
qs = Marten::DB::Query::Set(Tag).new.filter(name: "ruby")

qs.to_sql.should eq qs.query.to_sql
end
end

describe "#update" do
it "allows to update the records matching a given queryset with values specified as keyword arguments" do
user_1 = TestUser.create!(username: "abc", email: "abc@example.com", first_name: "John", last_name: "Doe")
Expand Down
27 changes: 27 additions & 0 deletions spec/marten/db/query/sql/query_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2198,6 +2198,33 @@ describe Marten::DB::Query::SQL::Query do
end
end

describe "#to_sql" do
it "produces the expected output" do
query = Marten::DB::Query::SQL::Query(Tag).new
query.add_query_node(Marten::DB::Query::Node.new(name__startswith: "r"))

for_mysql do
query.to_sql.should eq(
"SELECT app_tag.id, app_tag.name, app_tag.is_active " \
"FROM `app_tag` WHERE app_tag.name LIKE BINARY ? LIMIT 18446744073709551615"
)
end

for_postgresql do
query.to_sql.should eq(
"SELECT app_tag.id, app_tag.name, app_tag.is_active FROM \"app_tag\" WHERE app_tag.name LIKE $1"
)
end

for_sqlite do
query.to_sql.should eq(
"SELECT app_tag.id, app_tag.name, app_tag.is_active " \
"FROM \"app_tag\" WHERE app_tag.name LIKE ? ESCAPE '\\' LIMIT -1"
)
end
end
end

describe "#update_with" do
it "allows to update the records matching a given query and returns the number of affected rows" do
user_1 = TestUser.create!(username: "abc", email: "abc@example.com", first_name: "John", last_name: "Doe")
Expand Down
2 changes: 1 addition & 1 deletion src/marten/db/connection/base.cr
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ module Marten
# Allows to conveniently build a SQL statement by yielding an array of nillable strings.
def build_sql(&)
yield (clauses = [] of String?)
clauses.compact!.join " "
clauses.compact!.reject(&.try(&.empty?)).join " "
end

# Returns the identifier of the connection.
Expand Down
5 changes: 5 additions & 0 deletions src/marten/db/query/set.cr
Original file line number Diff line number Diff line change
Expand Up @@ -1074,6 +1074,11 @@ module Marten
inspect(io)
end

# Returns the SQL representation of the current query set.
def to_sql : String
@query.to_sql
end

# Updates all the records matched by the current query set with the passed values.
#
# This method allows to update all the records that are matched by the current query set with a hash or a named
Expand Down
4 changes: 4 additions & 0 deletions src/marten/db/query/sql/query.cr
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,10 @@ module Marten
)
end

def to_sql : String
build_query.first
end

def update_with(values : Hash(String | Symbol, Field::Any | DB::Model))
values_to_update = Hash(String, ::DB::Any).new
related_values_to_update = Hash(DB::Model.class, Hash(String | Symbol, Field::Any | DB::Model)).new
Expand Down

0 comments on commit b69d7e2

Please sign in to comment.