Skip to content

Commit

Permalink
Use quotes when referencing columns (#1059)
Browse files Browse the repository at this point in the history
* Use quotes when referencing columns. Fixes #792

* Added quoting to the generated where columns. Starting to fix specs

* More passing specs

* All specs passing again

* Applying suggestion
  • Loading branch information
jwoertink authored Aug 31, 2024
1 parent 84ffc29 commit bb63db8
Show file tree
Hide file tree
Showing 42 changed files with 312 additions and 258 deletions.
16 changes: 16 additions & 0 deletions db/migrations/20240818230651_create_notes.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
class CreateNotes::V20240818230651 < Avram::Migrator::Migration::V1
def migrate
create table_for(Note) do
primary_key id : Int64
add_timestamps
add from : String
add read : Bool, default: false
add text : String
add order : Int32, index: true
end
end

def rollback
drop table_for(Note)
end
end
6 changes: 3 additions & 3 deletions spec/avram/bool_criteria_spec.cr
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require "../spec_helper"

private class QueryMe < BaseModel
COLUMN_SQL = "users.id, users.created_at, users.updated_at, users.admin"
COLUMN_SQL = %("users"."id", "users"."created_at", "users"."updated_at", "users"."admin")

table users do
column admin : Bool
Expand All @@ -11,8 +11,8 @@ end
describe Bool::Lucky::Criteria do
describe "is" do
it "=" do
admin.eq(true).to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE users.admin = $1", "true"]
admin.eq(false).to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE users.admin = $1", "false"]
admin.eq(true).to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE "users"."admin" = $1), "true"]
admin.eq(false).to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE "users"."admin" = $1), "false"]
end
end
end
Expand Down
24 changes: 12 additions & 12 deletions spec/avram/criteria_spec.cr
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require "../spec_helper"

private class QueryMe < BaseModel
COLUMN_SQL = "users.id, users.created_at, users.updated_at, users.age, users.nickname"
COLUMN_SQL = %("users"."id", "users"."created_at", "users"."updated_at", "users"."age", "users"."nickname")

table users do
column age : Int32
Expand All @@ -12,67 +12,67 @@ end
describe Avram::Criteria do
describe "eq" do
it "uses =" do
age.eq(30).to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE users.age = $1", "30"]
age.eq(30).to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE "users"."age" = $1), "30"]
end
end

describe "nilable_eq" do
it "uses =" do
# Need to do this so that we get a nilable type
nilable_age = 30.as(Int32?)
age.nilable_eq(nilable_age).to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE users.age = $1", "30"]
age.nilable_eq(nilable_age).to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE "users"."age" = $1), "30"]
end

it "uses 'IS NULL' for comparisons to nil" do
# Need to do this so that we get a nilable type, but not just Nil
nilable = [nil, "name"].first
nickname.nilable_eq(nilable).to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE users.nickname IS NULL"]
nickname.nilable_eq(nilable).to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE "users"."nickname" IS NULL)]
end
end

describe "is_nil" do
it "uses IS NULL" do
nickname.is_nil.to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE users.nickname IS NULL"]
nickname.is_nil.to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE "users"."nickname" IS NULL)]
end
end

describe "is_not_nil" do
it "uses IS NOT NULL" do
nickname.is_not_nil.to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE users.nickname IS NOT NULL"]
nickname.is_not_nil.to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE "users"."nickname" IS NOT NULL)]
end
end

describe "gt" do
it "uses >" do
age.gt("30").to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE users.age > $1", "30"]
age.gt("30").to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE "users"."age" > $1), "30"]
end
end

describe "gte" do
it "uses >=" do
age.gte("30").to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE users.age >= $1", "30"]
age.gte("30").to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE "users"."age" >= $1), "30"]
end
end

describe "lt" do
it "uses <" do
age.lt("30").to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE users.age < $1", "30"]
age.lt("30").to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE "users"."age" < $1), "30"]
end
end

describe "lte" do
it "uses <=" do
age.lte("30").to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE users.age <= $1", "30"]
age.lte("30").to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE "users"."age" <= $1), "30"]
end
end

describe "not" do
it "negates the following criteria" do
age.not.gt("3").to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE users.age <= $1", "3"]
age.not.gt("3").to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE "users"."age" <= $1), "3"]
end

it "resets after having negated once" do
age.not.gt("3").age.eq("20").to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE users.age <= $1 AND users.age = $2", "3", "20"]
age.not.gt("3").age.eq("20").to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE "users"."age" <= $1 AND "users"."age" = $2), "3", "20"]
end
end
end
Expand Down
8 changes: 4 additions & 4 deletions spec/avram/float_criteria_spec.cr
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require "../spec_helper"

private class QueryMe < BaseModel
COLUMN_SQL = "purchases.id, purchases.created_at, purchases.updated_at, purchases.amount"
COLUMN_SQL = %("purchases"."id", "purchases"."created_at", "purchases"."updated_at", "purchases"."amount")

table purchases do
column amount : Float64
Expand All @@ -11,19 +11,19 @@ end
describe Float64::Lucky::Criteria do
describe "abs" do
it "uses ABS" do
amount.abs.eq(39.99).to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM purchases WHERE ABS(purchases.amount) = $1", "39.99"]
amount.abs.eq(39.99).to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM purchases WHERE ABS(\"purchases\".\"amount\") = $1", "39.99"]
end
end

describe "ceil" do
it "uses CEIL" do
amount.ceil.eq(40.0).to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM purchases WHERE CEIL(purchases.amount) = $1", "40.0"]
amount.ceil.eq(40.0).to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM purchases WHERE CEIL(\"purchases\".\"amount\") = $1", "40.0"]
end
end

describe "floor" do
it "uses FLOOR" do
amount.floor.eq(39.0).to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM purchases WHERE FLOOR(purchases.amount) = $1", "39.0"]
amount.floor.eq(39.0).to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM purchases WHERE FLOOR(\"purchases\".\"amount\") = $1", "39.0"]
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions spec/avram/insert_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ describe Avram::Insert do
it "inserts with a hash of String" do
params = {:first_name => "Paul", :last_name => "Smith"}
insert = Avram::Insert.new(table: :users, params: params)
insert.statement.should eq "insert into users(first_name, last_name) values($1, $2) returning *"
insert.statement.should eq %(insert into users("first_name", "last_name") values($1, $2) returning *)
insert.args.should eq ["Paul", "Smith"]
end

it "inserts with a hash of Nil" do
params = {:first_name => nil}
insert = Avram::Insert.new(table: :users, params: params)
insert.statement.should eq "insert into users(first_name) values($1) returning *"
insert.statement.should eq %(insert into users("first_name") values($1) returning *)
insert.args.should eq [nil]
end
end
Expand Down
4 changes: 2 additions & 2 deletions spec/avram/instrumentation_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ describe "Instrumentation" do
UserQuery.new.name("Bob").first?

event = Avram::Events::QueryEvent.logged_events.last
event.query.should contain("WHERE users.name = $1")
event.query.should contain(%(WHERE "users"."name" = $1))
event.args.to_s.should contain("Bob")
event.queryable.should eq("User")
end
Expand All @@ -23,7 +23,7 @@ describe "Instrumentation" do
UserQuery.new.name("Bob").select_count

event = Avram::Events::QueryEvent.logged_events.last
event.query.should contain("WHERE users.name = $1")
event.query.should contain(%(WHERE "users"."name" = $1))
event.args.to_s.should contain("Bob")
event.queryable.should eq("User")
end
Expand Down
8 changes: 4 additions & 4 deletions spec/avram/integer_criteria_spec.cr
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require "../spec_helper"

private class QueryMe < BaseModel
COLUMN_SQL = "transactions.id, transactions.created_at, transactions.updated_at, transactions.small_amount, transactions.amount, transactions.big_amount"
COLUMN_SQL = %("transactions"."id", "transactions"."created_at", "transactions"."updated_at", "transactions"."small_amount", "transactions"."amount", "transactions"."big_amount")

table transactions do
column small_amount : Int16
Expand All @@ -14,9 +14,9 @@ end
describe "Int::Lucky::Criteria" do
describe "abs" do
it "uses ABS" do
small_amount.abs.eq(4).to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM transactions WHERE ABS(transactions.small_amount) = $1", "4"]
amount.abs.eq(400).to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM transactions WHERE ABS(transactions.amount) = $1", "400"]
big_amount.abs.eq(40000).to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM transactions WHERE ABS(transactions.big_amount) = $1", "40000"]
small_amount.abs.eq(4).to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM transactions WHERE ABS(\"transactions\".\"small_amount\") = $1", "4"]
amount.abs.eq(400).to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM transactions WHERE ABS(\"transactions\".\"amount\") = $1", "400"]
big_amount.abs.eq(40000).to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM transactions WHERE ABS(\"transactions\".\"big_amount\") = $1", "40000"]
end
end
end
Expand Down
16 changes: 8 additions & 8 deletions spec/avram/join_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,43 @@ require "../spec_helper"
describe Avram::Join do
describe "builds statements using defaults" do
it "::INNER" do
Avram::Join::Inner.new(:users, :posts).to_sql.should eq "INNER JOIN posts ON users.id = posts.user_id"
Avram::Join::Inner.new(:users, :posts).to_sql.should eq %(INNER JOIN posts ON "users"."id" = "posts"."user_id")
end

it "::LEFT" do
Avram::Join::Left.new(:users, :posts).to_sql.should eq "LEFT JOIN posts ON users.id = posts.user_id"
Avram::Join::Left.new(:users, :posts).to_sql.should eq %(LEFT JOIN posts ON "users"."id" = "posts"."user_id")
end

it "::RIGHT" do
Avram::Join::Right.new(:users, :posts).to_sql.should eq "RIGHT JOIN posts ON users.id = posts.user_id"
Avram::Join::Right.new(:users, :posts).to_sql.should eq %(RIGHT JOIN posts ON "users"."id" = "posts"."user_id")
end

it "::FULL" do
Avram::Join::Full.new(:users, :posts).to_sql.should eq "FULL JOIN posts ON users.id = posts.user_id"
Avram::Join::Full.new(:users, :posts).to_sql.should eq %(FULL JOIN posts ON "users"."id" = "posts"."user_id")
end
end

it "allows custom to and from columns" do
Avram::Join::Inner.new(:users, :posts, primary_key: :uid, foreign_key: :author_id)
.to_sql
.should eq "INNER JOIN posts ON users.uid = posts.author_id"
.should eq %(INNER JOIN posts ON "users"."uid" = "posts"."author_id")
end

it "allows different boolean comparisons" do
Avram::Join::Inner.new(:users, :posts, comparison: "<@", foreign_key: :commenter_ids)
.to_sql
.should eq "INNER JOIN posts ON users.id <@ posts.commenter_ids"
.should eq %(INNER JOIN posts ON "users"."id" <@ "posts"."commenter_ids")
end

it "allows joining using related columns" do
Avram::Join::Inner.new(:employees, :managers, using: [:company_id, :department_id])
.to_sql
.should eq "INNER JOIN managers USING (company_id, department_id)"
.should eq %(INNER JOIN managers USING ("company_id", "department_id"))
end

it "allows aliasing the to table" do
Avram::Join::Inner.new(from: :purchases, to: :users, alias_to: :sellers, primary_key: :seller_id, foreign_key: :id)
.to_sql
.should eq "INNER JOIN users AS sellers ON purchases.seller_id = sellers.id"
.should eq %(INNER JOIN users AS sellers ON "purchases"."seller_id" = "sellers"."id")
end
end
22 changes: 11 additions & 11 deletions spec/avram/json_criteria_spec.cr
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require "../spec_helper"

private class QueryMe < BaseModel
COLUMN_SQL = "users.id, users.created_at, users.updated_at, users.preferences"
COLUMN_SQL = %("users"."id", "users"."created_at", "users"."updated_at", "users"."preferences")

table users do
column preferences : JSON::Any
Expand All @@ -11,59 +11,59 @@ end
describe JSON::Any::Lucky::Criteria do
describe "has_key" do
it "?" do
preferences.has_key("theme").to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE users.preferences ? $1", "theme"]
preferences.has_key("theme").to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE "users"."preferences" ? $1), "theme"]
end

it "negates with NOT()" do
preferences.not.has_key("theme").to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE NOT(users.preferences ? $1)", "theme"]
preferences.not.has_key("theme").to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE NOT("users"."preferences" ? $1)), "theme"]
end
end

describe "has_any_keys" do
it "?|" do
preferences.has_any_keys(["theme", "style"]).to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE users.preferences ?| $1", ["theme", "style"]]
preferences.has_any_keys(["theme", "style"]).to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE "users"."preferences" ?| $1), ["theme", "style"]]
end

it "negates with NOT()" do
preferences.not.has_any_keys(["theme", "style"]).to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE NOT(users.preferences ?| $1)", ["theme", "style"]]
preferences.not.has_any_keys(["theme", "style"]).to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE NOT("users"."preferences" ?| $1)), ["theme", "style"]]
end
end

describe "has_all_keys" do
it "?&" do
preferences.has_all_keys(["theme", "style"]).to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE users.preferences ?& $1", ["theme", "style"]]
preferences.has_all_keys(["theme", "style"]).to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE "users"."preferences" ?& $1), ["theme", "style"]]
end

it "negates with NOT()" do
preferences.not.has_all_keys(["theme", "style"]).to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE NOT(users.preferences ?& $1)", ["theme", "style"]]
preferences.not.has_all_keys(["theme", "style"]).to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE NOT("users"."preferences" ?& $1)), ["theme", "style"]]
end
end

describe "includes" do
it "@>" do
json = JSON::Any.new({"theme" => JSON::Any.new("dark")})
critera = preferences.includes(json)
critera.to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE users.preferences @> $1", "{\"theme\":\"dark\"}"]
critera.to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE "users"."preferences" @> $1), %({"theme":"dark"})]
end

it "negates with NOT()" do
json = JSON::Any.new({"theme" => JSON::Any.new("dark")})
critera = preferences.not.includes(json)
critera.to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE NOT(users.preferences @> $1)", "{\"theme\":\"dark\"}"]
critera.to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE NOT("users"."preferences" @> $1)), %({"theme":"dark"})]
end
end

describe "in" do
it "<@" do
json = JSON::Any.new({"theme" => JSON::Any.new("dark"), "style" => JSON::Any.new("cyberpunk"), "version" => JSON::Any.new(2i64)})
critera = preferences.in(json)
critera.to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE users.preferences <@ $1", "{\"theme\":\"dark\",\"style\":\"cyberpunk\",\"version\":2}"]
critera.to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE "users"."preferences" <@ $1), %({"theme":"dark","style":"cyberpunk","version":2})]
end

it "negates with NOT()" do
json = JSON::Any.new({"theme" => JSON::Any.new("dark"), "style" => JSON::Any.new("cyberpunk"), "version" => JSON::Any.new(2i64)})
critera = preferences.not.in(json)
critera.to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE NOT(users.preferences <@ $1)", "{\"theme\":\"dark\",\"style\":\"cyberpunk\",\"version\":2}"]
critera.to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE NOT("users"."preferences" <@ $1)), %({"theme":"dark","style":"cyberpunk","version":2})]
end
end
end
Expand Down
Loading

0 comments on commit bb63db8

Please sign in to comment.