Skip to content

Commit

Permalink
Fix anykeyh#28 : Add double quote around schema, table and column nam…
Browse files Browse the repository at this point in the history
…e to allow

reserved keywords usage on it.
  • Loading branch information
Yacine Petitprez committed Aug 13, 2018
1 parent 6b98ec6 commit 66eeb78
Show file tree
Hide file tree
Showing 28 changed files with 261 additions and 172 deletions.
16 changes: 15 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,25 @@
## Features
- Improved Model build/create methods, allowing to pass arguments instead of NamedTuple


## Bug fixes
- Escaping table, columns and schema name to allow Clear to works on any model names.
- This is very demanding work as it turns out table and columns naming are used everywhere
in the ORM. Please give me feedback in case of any issues !

## Breaking changes
- Renaming `insert` method on `InsertQuery` to `values`, making API more elegant.
- Usage of `var` in Expression engine has been changed and is now different from raw:
- `var` provide simple way to construct `[schema].table.field` structure,
with escaped table, field and schema keywords.
- `raw` works as usual, printing the raw string fragment to you condition.
- Therefore:
```crystal
where{ var("a.b") == 1 } # Wrong now! => WHERE "a.b" = 1
# Must be changed by:
where{ var("a", "b") == 1 } # OR
where{ raw("a.b") }
```
TL;DR, if you currently use `var` function, please use `raw` instead from now.
# v0.3
Expand Down
22 changes: 11 additions & 11 deletions spec/extensions/jsonb_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -46,48 +46,48 @@ module JSONBSpec
it "use -> operator when it cannot test presence" do
Clear::SQL.select("*").from("users")
.where { data.jsonb("personal email").cast("text").like "%@gmail.com" }.to_sql
.should eq %(SELECT * FROM users WHERE (data->'personal email'::text LIKE '%@gmail.com'))
.should eq %(SELECT * FROM users WHERE ("data"->'personal email'::text LIKE '%@gmail.com'))

# v-- Complex call
Clear::SQL.select.from("users")
.where { data.jsonb("test") == call_function(data.jsonb("a.b.c")) }.to_sql
.should eq %(SELECT * FROM users WHERE (data->'test' = call_function(data->'a'->'b'->'c')))
.should eq %(SELECT * FROM users WHERE ("data"->'test' = call_function("data"->'a'->'b'->'c')))
end

it "uses @> operator when it can !" do
Clear::SQL.select("*").from("users")
Clear::SQL.select("*").from(:users)
.where {
(data.jsonb("security.role") == "admin") &
(data.jsonb("security.level") == 1)
}.to_sql
.should eq "SELECT * FROM users WHERE (data @> '{\"security\":{\"role\":\"admin\"}}' AND " +
"data @> '{\"security\":{\"level\":1}}')"
.should eq "SELECT * FROM \"users\" WHERE (\"data\" @> '{\"security\":{\"role\":\"admin\"}}' AND " +
"\"data\" @> '{\"security\":{\"level\":1}}')"
end

it "check existence of a key" do
Clear::SQL.select.from("users")
Clear::SQL.select.from(:users)
.where { data.jsonb_key_exists?("test") }
.to_sql
.should eq "SELECT * FROM users WHERE (data ? 'test')"
.should eq "SELECT * FROM \"users\" WHERE (\"data\" ? 'test')"

Clear::SQL.select.from("users")
.where { data.jsonb("a").jsonb_key_exists?("test") }
.to_sql
.should eq "SELECT * FROM users WHERE (data->'a' ? 'test')"
.should eq "SELECT * FROM users WHERE (\"data\"->'a' ? 'test')"
end

it "check existence of any key" do
Clear::SQL.select.from("users")
Clear::SQL.select.from(:users)
.where { data.jsonb_any_key_exists?(["a", 0]) }
.to_sql
.should eq "SELECT * FROM users WHERE (data ?| array['a', 0])"
.should eq "SELECT * FROM \"users\" WHERE (\"data\" ?| array['a', 0])"
end

it "check existence of all keys" do
Clear::SQL.select.from("users")
.where { data.jsonb("a").jsonb_all_keys_exists?(["a", "b"]) }
.to_sql
.should eq "SELECT * FROM users WHERE (data->'a' ?& array['a', 'b'])"
.should eq "SELECT * FROM users WHERE (\"data\"->'a' ?& array['a', 'b'])"
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion spec/model/cache_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ module CacheSpec
end
Clear::Model::QueryCache.cache_hitted.should eq(4) # Number of posts

Category.query.with_users { |q| q.order_by("users.id": :asc) }.order_by("id": :asc).each do |c|
Category.query.with_users { |q| q.order_by("users.id", "asc") }.order_by("id", "asc").each do |c|
c.users.each do |user|
c.id.not_nil!
user.id.not_nil!
Expand Down
22 changes: 11 additions & 11 deletions spec/model/model_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -414,12 +414,12 @@ module ModelSpec
p = Post.create!({title: "Post about Dogs", user_id: u.id, category_id: c.id})

# Categories should return 1, as we remove duplicate
u.categories.to_sql.should eq "SELECT DISTINCT ON (\"model_categories\".\"id\") \"model_categories\".* " +
"FROM \"model_categories\" " +
"INNER JOIN \"model_posts\" ON " +
"((\"model_posts\".\"category_id\" = \"model_categories\".\"id\")) " +
"WHERE (\"model_posts\".\"user_id\" = 1)"
u.categories.count.should eq(1)
u.categories.to_sql.should eq "SELECT DISTINCT ON (model_categories.id) model_categories.* " +
"FROM model_categories " +
"INNER JOIN model_posts ON " +
"((model_posts.category_id = model_categories.id)) " +
"WHERE (model_posts.user_id = 1)"
end
end
end
Expand All @@ -433,9 +433,9 @@ module ModelSpec

Post.create!({title: "A Post", user_id: u.id})

Post.query.join("model_users") { model_posts.user_id == model_users.id }.to_sql
.should eq "SELECT model_posts.* FROM model_posts INNER JOIN model_users " +
"ON ((model_posts.user_id = model_users.id))"
Post.query.join(:model_users) { model_posts.user_id == model_users.id }.to_sql
.should eq "SELECT \"model_posts\".* FROM \"model_posts\" INNER JOIN \"model_users\" " +
"ON ((\"model_posts\".\"user_id\" = \"model_users\".\"id\"))"
end
end

Expand All @@ -445,11 +445,11 @@ module ModelSpec
u = User.create!({first_name: "Join User"})
Post.create!({title: "A Post", user_id: u.id})

user_with_a_post_minimum = User.query.distinct.join("model_posts") { model_posts.user_id == model_users.id }
user_with_a_post_minimum = User.query.distinct.join(:model_posts) { model_posts.user_id == model_users.id }

user_with_a_post_minimum.to_sql.should eq \
"SELECT DISTINCT model_users.* FROM model_users INNER JOIN " +
"model_posts ON ((model_posts.user_id = model_users.id))"
"SELECT DISTINCT \"model_users\".* FROM \"model_users\" INNER JOIN " +
"\"model_posts\" ON ((\"model_posts\".\"user_id\" = \"model_users\".\"id\"))"

user_with_a_post_minimum.with_posts.each { } # Should just execute
end
Expand Down
6 changes: 3 additions & 3 deletions spec/model/scope_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ module ScopeSpec

ScopeModel.create! #Without value

ScopeModel.no_value.to_sql.should eq("SELECT * FROM scope_models WHERE (value IS NULL)")
ScopeModel.no_value.to_sql.should eq("SELECT * FROM \"scope_models\" WHERE (\"value\" IS NULL)")
ScopeModel.no_value.count.should eq 1
ScopeModel.with_value(1).to_sql.should eq("SELECT * FROM scope_models WHERE (value = 1)")
ScopeModel.with_value(1).to_sql.should eq("SELECT * FROM \"scope_models\" WHERE (\"value\" = 1)")
ScopeModel.with_value(1).count.should eq 1
ScopeModel.with_values(1,2,3).where{id < 10}.to_sql.should eq("SELECT * FROM scope_models WHERE value IN (1, 2, 3) AND (id < 10)")
ScopeModel.with_values(1,2,3).where{id < 10}.to_sql.should eq("SELECT * FROM \"scope_models\" WHERE \"value\" IN (1, 2, 3) AND (\"id\" < 10)")
ScopeModel.with_values(1,2,3).count.should eq 3
end

Expand Down
22 changes: 11 additions & 11 deletions spec/sql/delete_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ module DeleteSpec

def complex_query
Clear::SQL.select.from(:users)
.join(:role_users) { role_users.user_id == users.id }
.join(:roles) { role_users.role_id == roles.id }
.where({role: ["admin", "superadmin"]})
.order_by({priority: :desc, name: :asc})
.limit(1)
.join(:role_users) { role_users.user_id == users.id }
.join(:roles) { role_users.role_id == roles.id }
.where({role: ["admin", "superadmin"]})
.order_by({priority: :desc, name: :asc})
.limit(1)
end

describe "Clear::SQL" do
Expand All @@ -30,12 +30,12 @@ module DeleteSpec
end

it "can create a delete with where parameter" do
r = delete_request.from("table").where({id: complex_query})
r.to_sql.should eq "DELETE FROM table WHERE id IN (SELECT * " +
"FROM users " +
"INNER JOIN role_users ON ((role_users.user_id = users.id)) " +
"INNER JOIN roles ON ((role_users.role_id = roles.id)) " +
"WHERE role IN ('admin', 'superadmin') " +
r = delete_request.from(:table).where({id: complex_query})
r.to_sql.should eq "DELETE FROM \"table\" WHERE \"id\" IN (SELECT * " +
"FROM \"users\" " +
"INNER JOIN \"role_users\" ON ((\"role_users\".\"user_id\" = \"users\".\"id\")) " +
"INNER JOIN \"roles\" ON ((\"role_users\".\"role_id\" = \"roles\".\"id\")) " +
"WHERE \"role\" IN ('admin', 'superadmin') " +
"ORDER BY priority DESC, name ASC " +
"LIMIT 1)"
end
Expand Down
10 changes: 5 additions & 5 deletions spec/sql/insert_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,29 @@ module InsertSpec
describe "InsertQuery" do
it "can build an insert" do
insert_request.values({a: "c", b: 12}).to_sql.should eq(
"INSERT INTO users (a, b) VALUES ('c', 12)"
"INSERT INTO \"users\" (\"a\", \"b\") VALUES ('c', 12)"
)
end

it "can build an insert from sql" do
insert_request.values(
Clear::SQL.select.from("old_users")
Clear::SQL.select.from(:old_users)
.where { old_users.id > 100 }
).to_sql.should eq (
"INSERT INTO users (SELECT * FROM old_users WHERE (old_users.id > 100))"
"INSERT INTO \"users\" (SELECT * FROM \"old_users\" WHERE (\"old_users\".\"id\" > 100))"
)
end

it "can build an empty insert?" do
insert_request.to_sql.should eq (
"INSERT INTO users DEFAULT VALUES"
"INSERT INTO \"users\" DEFAULT VALUES"
)
end

it "can insert unsafe values" do
insert_request.values({created_at: Clear::Expression.unsafe("NOW()")})
.to_sql
.should eq "INSERT INTO users (created_at) VALUES (NOW())"
.should eq "INSERT INTO \"users\" (\"created_at\") VALUES (NOW())"
end
end
end
Expand Down
Loading

0 comments on commit 66eeb78

Please sign in to comment.