From 90d4cdf0575929ac141ebd6aceb584649e017219 Mon Sep 17 00:00:00 2001 From: Jeremy Woertink Date: Sun, 18 Aug 2024 17:09:19 -0700 Subject: [PATCH 1/5] Use quotes when referencing columns. Fixes #792 --- db/migrations/20240818230651_create_notes.cr | 15 +++++++++++++++ spec/avram/model_spec.cr | 13 +++++++++++++ spec/support/factories/note_factory.cr | 4 ++++ spec/support/models/note.cr | 10 ++++++++++ src/avram/insert.cr | 4 ++-- src/avram/migrator/columns/base.cr | 2 +- src/avram/migrator/columns/primary_keys/base.cr | 2 +- .../columns/primary_keys/uuid_primary_key.cr | 2 +- src/avram/query_builder.cr | 2 +- 9 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 db/migrations/20240818230651_create_notes.cr create mode 100644 spec/support/factories/note_factory.cr create mode 100644 spec/support/models/note.cr diff --git a/db/migrations/20240818230651_create_notes.cr b/db/migrations/20240818230651_create_notes.cr new file mode 100644 index 000000000..2b013bfd1 --- /dev/null +++ b/db/migrations/20240818230651_create_notes.cr @@ -0,0 +1,15 @@ +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 + end + end + + def rollback + drop table_for(Note) + end +end diff --git a/spec/avram/model_spec.cr b/spec/avram/model_spec.cr index 04a858cc1..4aeb29fbe 100644 --- a/spec/avram/model_spec.cr +++ b/spec/avram/model_spec.cr @@ -91,6 +91,19 @@ describe Avram::Model do user.email.to_s.should eq "foo@bar.com" end + it "allows columns named the same as reserved SQL names" do + NoteFactory.create(&.from("Me").text("hi").read(true)) + note = NoteQuery.new.from("Me").first + note.from.should eq("Me") + note.text.should eq("hi") + note.read?.should eq(true) + Note::SaveOperation.update!(note, read: false) + note = note.reload + note.read?.should eq(false) + Note::DeleteOperation.delete!(note) + NoteQuery.new.select_count.should eq(0) + end + describe "reload" do it "can reload a model" do user = UserFactory.create &.name("Original Name") diff --git a/spec/support/factories/note_factory.cr b/spec/support/factories/note_factory.cr new file mode 100644 index 000000000..58d0a33ac --- /dev/null +++ b/spec/support/factories/note_factory.cr @@ -0,0 +1,4 @@ +class NoteFactory < BaseFactory + def initialize + end +end diff --git a/spec/support/models/note.cr b/spec/support/models/note.cr new file mode 100644 index 000000000..ff9d739ff --- /dev/null +++ b/spec/support/models/note.cr @@ -0,0 +1,10 @@ +class Note < BaseModel + table do + column from : String + column read : Bool = false + column text : String + end +end + +class NoteQuery < Note::BaseQuery +end diff --git a/src/avram/insert.cr b/src/avram/insert.cr index fd218b16a..a8d01d1da 100644 --- a/src/avram/insert.cr +++ b/src/avram/insert.cr @@ -12,7 +12,7 @@ class Avram::Insert if @column_names.empty? "*" else - @column_names.join(", ") { |column| "#{@table}.#{column}" } + @column_names.join(", ") { |column| %("#{@table}"."#{column}") } end end @@ -21,7 +21,7 @@ class Avram::Insert end private def fields : String - @params.keys.join(", ") + @params.keys.join(", ") { |col| %("#{col}") } end private def values_placeholders : String diff --git a/src/avram/migrator/columns/base.cr b/src/avram/migrator/columns/base.cr index 8a9ae16b7..badeae8d3 100644 --- a/src/avram/migrator/columns/base.cr +++ b/src/avram/migrator/columns/base.cr @@ -52,7 +52,7 @@ abstract class Avram::Migrator::Columns::Base private def build_add_statement : String String.build do |row| - row << name.to_s + row << %("#{name}") row << " " row << column_type + as_array_type row << null_fragment diff --git a/src/avram/migrator/columns/primary_keys/base.cr b/src/avram/migrator/columns/primary_keys/base.cr index 7fc0d8369..13fe6e258 100644 --- a/src/avram/migrator/columns/primary_keys/base.cr +++ b/src/avram/migrator/columns/primary_keys/base.cr @@ -6,6 +6,6 @@ abstract class Avram::Migrator::Columns::PrimaryKeys::Base abstract def column_type def build : String - %( #{name} #{column_type} PRIMARY KEY) + %( "#{name}" #{column_type} PRIMARY KEY) end end diff --git a/src/avram/migrator/columns/primary_keys/uuid_primary_key.cr b/src/avram/migrator/columns/primary_keys/uuid_primary_key.cr index abfe318af..55aa06f4d 100644 --- a/src/avram/migrator/columns/primary_keys/uuid_primary_key.cr +++ b/src/avram/migrator/columns/primary_keys/uuid_primary_key.cr @@ -10,7 +10,7 @@ module Avram::Migrator::Columns::PrimaryKeys end def build : String - %( #{name} #{column_type} PRIMARY KEY DEFAULT gen_random_uuid()) + %( "#{name}" #{column_type} PRIMARY KEY DEFAULT gen_random_uuid()) end end end diff --git a/src/avram/query_builder.cr b/src/avram/query_builder.cr index 1d67e8703..b25c39fda 100644 --- a/src/avram/query_builder.cr +++ b/src/avram/query_builder.cr @@ -268,7 +268,7 @@ class Avram::QueryBuilder end def select(selection : Array(ColumnName)) : self - @selections = selection.join(", ") { |column| "#{@table}.#{column}" } + @selections = selection.join(", ") { |column| %("#{@table}"."#{column}") } self end From 1ad31133080e98b47c49bce89fe13f44dd4c65d6 Mon Sep 17 00:00:00 2001 From: Jeremy Woertink Date: Tue, 20 Aug 2024 16:44:02 -0700 Subject: [PATCH 2/5] Added quoting to the generated where columns. Starting to fix specs --- spec/avram/bool_criteria_spec.cr | 6 +++--- spec/avram/float_criteria_spec.cr | 8 ++++---- spec/avram/integer_criteria_spec.cr | 8 ++++---- src/avram/base_query_template.cr | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/spec/avram/bool_criteria_spec.cr b/spec/avram/bool_criteria_spec.cr index a73d4da93..0ae59bb6e 100644 --- a/spec/avram/bool_criteria_spec.cr +++ b/spec/avram/bool_criteria_spec.cr @@ -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 @@ -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 diff --git a/spec/avram/float_criteria_spec.cr b/spec/avram/float_criteria_spec.cr index 9a2dc145f..902c6b615 100644 --- a/spec/avram/float_criteria_spec.cr +++ b/spec/avram/float_criteria_spec.cr @@ -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 @@ -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 diff --git a/spec/avram/integer_criteria_spec.cr b/spec/avram/integer_criteria_spec.cr index 27396c545..8286aa6b6 100644 --- a/spec/avram/integer_criteria_spec.cr +++ b/spec/avram/integer_criteria_spec.cr @@ -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 @@ -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 diff --git a/src/avram/base_query_template.cr b/src/avram/base_query_template.cr index ace778178..5269f5a5c 100644 --- a/src/avram/base_query_template.cr +++ b/src/avram/base_query_template.cr @@ -10,7 +10,7 @@ class Avram::BaseQueryTemplate macro generate_criteria_method(name, type) def \{{ name }} - \{{ type }}.adapter.criteria(self, "#{table_name}.\{{ name }}") + \{{ type }}.adapter.criteria(self, %("#{table_name}"."\{{ name }}")) end end From 46dc3dfbbd9f24c66ab3846f485584cc09770bef Mon Sep 17 00:00:00 2001 From: Jeremy Woertink Date: Sun, 25 Aug 2024 11:29:14 -0700 Subject: [PATCH 3/5] More passing specs --- db/migrations/20240818230651_create_notes.cr | 1 + .../migrator/alter_table_statement_spec.cr | 72 ++++++------ .../migrator/create_index_statement_spec.cr | 16 +-- .../migrator/create_table_statement_spec.cr | 110 +++++++++--------- spec/avram/model_spec.cr | 14 +-- spec/avram/query_builder/merge_spec.cr | 2 +- spec/avram/query_builder_spec.cr | 10 +- spec/avram/queryable_spec.cr | 82 ++++++------- spec/avram/string_criteria_spec.cr | 26 ++--- spec/avram/time_criteria_spec.cr | 49 ++++---- spec/support/models/admin.cr | 2 +- spec/support/models/article.cr | 2 +- spec/support/models/beat.cr | 2 +- spec/support/models/blob.cr | 1 + spec/support/models/bucket.cr | 2 +- spec/support/models/business.cr | 2 +- spec/support/models/comment.cr | 1 + spec/support/models/company.cr | 1 + spec/support/models/employee.cr | 1 + spec/support/models/issue.cr | 2 +- spec/support/models/note.cr | 1 + spec/support/models/post.cr | 1 + spec/support/models/user.cr | 2 +- src/avram/join.cr | 4 +- src/avram/migrator/create_index_statement.cr | 5 +- src/avram/migrator/create_table_statement.cr | 2 +- 26 files changed, 211 insertions(+), 202 deletions(-) diff --git a/db/migrations/20240818230651_create_notes.cr b/db/migrations/20240818230651_create_notes.cr index 2b013bfd1..c6c003bf1 100644 --- a/db/migrations/20240818230651_create_notes.cr +++ b/db/migrations/20240818230651_create_notes.cr @@ -6,6 +6,7 @@ class CreateNotes::V20240818230651 < Avram::Migrator::Migration::V1 add from : String add read : Bool, default: false add text : String + add order : Int32, index: true end end diff --git a/spec/avram/migrator/alter_table_statement_spec.cr b/spec/avram/migrator/alter_table_statement_spec.cr index 3862fcc9d..f5d84aeb6 100644 --- a/spec/avram/migrator/alter_table_statement_spec.cr +++ b/spec/avram/migrator/alter_table_statement_spec.cr @@ -29,25 +29,25 @@ describe Avram::Migrator::AlterTableStatement do built.statements[2].should eq <<-SQL ALTER TABLE users - ADD name text, - ADD email text, - ADD nickname text NOT NULL, - ADD age int4 NOT NULL DEFAULT '1', - ADD num bigint NOT NULL DEFAULT '1', - ADD amount_paid decimal(10,5) NOT NULL DEFAULT '1.0', - ADD completed boolean NOT NULL DEFAULT 'false', - ADD meta jsonb NOT NULL DEFAULT '{"default":"value"}', - ADD joined_at timestamptz NOT NULL DEFAULT NOW(), - ADD updated_at timestamptz, - ADD future_time timestamptz NOT NULL DEFAULT '#{Time.local.to_utc}', - ADD new_id uuid NOT NULL DEFAULT '46d9b2f0-0718-4d4c-a5a1-5af81d5b11e0', - ADD numbers int4[], + ADD "name" text, + ADD "email" text, + ADD "nickname" text NOT NULL, + ADD "age" int4 NOT NULL DEFAULT '1', + ADD "num" bigint NOT NULL DEFAULT '1', + ADD "amount_paid" decimal(10,5) NOT NULL DEFAULT '1.0', + ADD "completed" boolean NOT NULL DEFAULT 'false', + ADD "meta" jsonb NOT NULL DEFAULT '{"default":"value"}', + ADD "joined_at" timestamptz NOT NULL DEFAULT NOW(), + ADD "updated_at" timestamptz, + ADD "future_time" timestamptz NOT NULL DEFAULT '#{Time.local.to_utc}', + ADD "new_id" uuid NOT NULL DEFAULT '46d9b2f0-0718-4d4c-a5a1-5af81d5b11e0', + ADD "numbers" int4[], DROP old_column, DROP employee_id; SQL - built.statements[3].should eq "CREATE UNIQUE INDEX users_age_index ON users USING btree (age);" - built.statements[4].should eq "CREATE INDEX users_num_index ON users USING btree (num);" + built.statements[3].should eq %(CREATE UNIQUE INDEX users_age_index ON users USING btree ("age");) + built.statements[4].should eq %(CREATE INDEX users_num_index ON users USING btree ("num");) built.statements[5].should eq "UPDATE users SET email = 'noreply@lucky.com';" built.statements[6].should eq "ALTER TABLE users ALTER COLUMN email SET NOT NULL;" built.statements[7].should eq "UPDATE users SET updated_at = NOW();" @@ -117,7 +117,7 @@ describe Avram::Migrator::AlterTableStatement do end built.statements.size.should eq 3 - built.statements[0].should eq "ALTER TABLE users\n ADD confirmed_at timestamptz;" + built.statements[0].should eq %(ALTER TABLE users\n ADD "confirmed_at" timestamptz;) built.statements[1].should eq "UPDATE users SET confirmed_at = NOW();" built.statements[2].should eq "ALTER TABLE users ALTER COLUMN confirmed_at SET NOT NULL;" end @@ -128,7 +128,7 @@ describe Avram::Migrator::AlterTableStatement do end built.statements.size.should eq 2 - built.statements[0].should eq "ALTER TABLE users\n ADD confirmed_at timestamptz;" + built.statements[0].should eq %(ALTER TABLE users\n ADD "confirmed_at" timestamptz;) built.statements[1].should eq "UPDATE users SET confirmed_at = NOW();" end @@ -138,7 +138,7 @@ describe Avram::Migrator::AlterTableStatement do end built.statements.size.should eq 3 - built.statements[0].should eq "ALTER TABLE users\n ADD admin boolean;" + built.statements[0].should eq %(ALTER TABLE users\n ADD "admin" boolean;) built.statements[1].should eq "UPDATE users SET admin = 'false';" built.statements[2].should eq "ALTER TABLE users ALTER COLUMN admin SET NOT NULL;" end @@ -157,20 +157,20 @@ describe Avram::Migrator::AlterTableStatement do built.statements.first.should eq <<-SQL ALTER TABLE comments - ADD user_id bigint NOT NULL REFERENCES users ON DELETE CASCADE, - ADD post_id bigint REFERENCES posts ON DELETE RESTRICT, - ADD category_label_id bigint NOT NULL REFERENCES custom_table ON DELETE SET NULL, - ADD employee_id bigint NOT NULL REFERENCES users ON DELETE CASCADE, - ADD line_item_id uuid NOT NULL REFERENCES line_items ON DELETE CASCADE, - ADD subscription_item_id bigint NOT NULL REFERENCES subscription_items ON DELETE CASCADE; + ADD "user_id" bigint NOT NULL REFERENCES users ON DELETE CASCADE, + ADD "post_id" bigint REFERENCES posts ON DELETE RESTRICT, + ADD "category_label_id" bigint NOT NULL REFERENCES custom_table ON DELETE SET NULL, + ADD "employee_id" bigint NOT NULL REFERENCES users ON DELETE CASCADE, + ADD "line_item_id" uuid NOT NULL REFERENCES line_items ON DELETE CASCADE, + ADD "subscription_item_id" bigint NOT NULL REFERENCES subscription_items ON DELETE CASCADE; SQL - built.statements[1].should eq "CREATE UNIQUE INDEX comments_user_id_index ON comments USING btree (user_id);" - built.statements[2].should eq "CREATE INDEX comments_post_id_index ON comments USING btree (post_id);" - built.statements[3].should eq "CREATE INDEX comments_category_label_id_index ON comments USING btree (category_label_id);" - built.statements[4].should eq "CREATE INDEX comments_employee_id_index ON comments USING btree (employee_id);" - built.statements[5].should eq "CREATE INDEX comments_line_item_id_index ON comments USING btree (line_item_id);" - built.statements[6].should eq "CREATE INDEX comments_subscription_item_id_index ON comments USING btree (subscription_item_id);" + built.statements[1].should eq %(CREATE UNIQUE INDEX comments_user_id_index ON comments USING btree ("user_id");) + built.statements[2].should eq %(CREATE INDEX comments_post_id_index ON comments USING btree ("post_id");) + built.statements[3].should eq %(CREATE INDEX comments_category_label_id_index ON comments USING btree ("category_label_id");) + built.statements[4].should eq %(CREATE INDEX comments_employee_id_index ON comments USING btree ("employee_id");) + built.statements[5].should eq %(CREATE INDEX comments_line_item_id_index ON comments USING btree ("line_item_id");) + built.statements[6].should eq %(CREATE INDEX comments_subscription_item_id_index ON comments USING btree ("subscription_item_id");) built.statements[7].should eq "UPDATE comments SET line_item_id = 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11';" end @@ -189,8 +189,8 @@ describe Avram::Migrator::AlterTableStatement do end built.statements.size.should eq 4 - built.statements[0].should eq "ALTER TABLE comments\n ADD line_item_id uuid NOT NULL REFERENCES line_items ON DELETE CASCADE;" - built.statements[1].should eq "CREATE INDEX comments_line_item_id_index ON comments USING btree (line_item_id);" + built.statements[0].should eq %(ALTER TABLE comments\n ADD "line_item_id" uuid NOT NULL REFERENCES line_items ON DELETE CASCADE;) + built.statements[1].should eq %(CREATE INDEX comments_line_item_id_index ON comments USING btree ("line_item_id");) built.statements[2].should eq "UPDATE comments SET line_item_id = 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11';" built.statements[3].should eq "ALTER TABLE comments ALTER COLUMN line_item_id SET NOT NULL;" end @@ -201,8 +201,8 @@ describe Avram::Migrator::AlterTableStatement do end built.statements.size.should eq 3 - built.statements[0].should eq "ALTER TABLE comments\n ADD line_item_id uuid REFERENCES line_items ON DELETE CASCADE;" - built.statements[1].should eq "CREATE INDEX comments_line_item_id_index ON comments USING btree (line_item_id);" + built.statements[0].should eq %(ALTER TABLE comments\n ADD "line_item_id" uuid REFERENCES line_items ON DELETE CASCADE;) + built.statements[1].should eq %(CREATE INDEX comments_line_item_id_index ON comments USING btree ("line_item_id");) built.statements[2].should eq "UPDATE comments SET line_item_id = 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11';" end end @@ -213,7 +213,7 @@ describe Avram::Migrator::AlterTableStatement do add_belongs_to guest : User?, on_delete: :cascade, fill_existing_with: :nothing end - built.statements[1].should eq "CREATE INDEX challenges_guest_id_index ON challenges USING btree (guest_id);" + built.statements[1].should eq %(CREATE INDEX challenges_guest_id_index ON challenges USING btree ("guest_id");) built.statements.size.should eq(2) end end @@ -233,7 +233,7 @@ describe Avram::Migrator::AlterTableStatement do built.statements[2].should eq <<-SQL ALTER TABLE IF EXISTS users - ADD name text; + ADD "name" text; SQL end end diff --git a/spec/avram/migrator/create_index_statement_spec.cr b/spec/avram/migrator/create_index_statement_spec.cr index a0f77046f..a759a31c7 100644 --- a/spec/avram/migrator/create_index_statement_spec.cr +++ b/spec/avram/migrator/create_index_statement_spec.cr @@ -3,35 +3,35 @@ require "../../spec_helper" describe Avram::Migrator::CreateIndexStatement do it "generates correct CREATE INDEX sql" do statement = Avram::Migrator::CreateIndexStatement.new(:users, :email).build - statement.should eq "CREATE INDEX users_email_index ON users USING btree (email);" + statement.should eq %(CREATE INDEX users_email_index ON users USING btree ("email");) statement = Avram::Migrator::CreateIndexStatement.new(:users, columns: :email, using: :btree, unique: true).build - statement.should eq "CREATE UNIQUE INDEX users_email_index ON users USING btree (email);" + statement.should eq %(CREATE UNIQUE INDEX users_email_index ON users USING btree ("email");) end it "supports other index types" do statement = Avram::Migrator::CreateIndexStatement.new(:users, columns: :tags, using: :hash).build - statement.should eq "CREATE INDEX users_tags_index ON users USING hash (tags);" + statement.should eq %(CREATE INDEX users_tags_index ON users USING hash ("tags");) statement = Avram::Migrator::CreateIndexStatement.new(:users, columns: :tags, using: :gist).build - statement.should eq "CREATE INDEX users_tags_index ON users USING gist (tags);" + statement.should eq %(CREATE INDEX users_tags_index ON users USING gist ("tags");) statement = Avram::Migrator::CreateIndexStatement.new(:users, columns: :tags, using: :gin).build - statement.should eq "CREATE INDEX users_tags_index ON users USING gin (tags);" + statement.should eq %(CREATE INDEX users_tags_index ON users USING gin ("tags");) statement = Avram::Migrator::CreateIndexStatement.new(:users, columns: :tags, using: :brin).build - statement.should eq "CREATE INDEX users_tags_index ON users USING brin (tags);" + statement.should eq %(CREATE INDEX users_tags_index ON users USING brin ("tags");) end it "generates correct multi-column index sql" do statement = Avram::Migrator::CreateIndexStatement.new(:users, columns: [:email, :username], using: :btree, unique: true).build - statement.should eq "CREATE UNIQUE INDEX users_email_username_index ON users USING btree (email, username);" + statement.should eq %(CREATE UNIQUE INDEX users_email_username_index ON users USING btree ("email", "username");) end context "custom index name" do it "generates correct CREATE INDEX sql with given name" do statement = Avram::Migrator::CreateIndexStatement.new(:users, :email, name: :custom_index_name).build - statement.should eq "CREATE INDEX custom_index_name ON users USING btree (email);" + statement.should eq %(CREATE INDEX custom_index_name ON users USING btree ("email");) end end end diff --git a/spec/avram/migrator/create_table_statement_spec.cr b/spec/avram/migrator/create_table_statement_spec.cr index 0e032dbf3..f433eaebb 100644 --- a/spec/avram/migrator/create_table_statement_spec.cr +++ b/spec/avram/migrator/create_table_statement_spec.cr @@ -28,17 +28,17 @@ describe Avram::Migrator::CreateTableStatement do built.statements.size.should eq 1 built.statements.first.should eq <<-SQL CREATE TABLE users ( - id serial4 PRIMARY KEY, - created_at timestamptz NOT NULL DEFAULT NOW(), - updated_at timestamptz NOT NULL DEFAULT NOW(), - name text NOT NULL, - age int4 NOT NULL, - completed boolean NOT NULL, - joined_at timestamptz NOT NULL, - amount_paid decimal(10,2) NOT NULL, - email text, - meta jsonb, - reference uuid NOT NULL); + "id" serial4 PRIMARY KEY, + "created_at" timestamptz NOT NULL DEFAULT NOW(), + "updated_at" timestamptz NOT NULL DEFAULT NOW(), + "name" text NOT NULL, + "age" int4 NOT NULL, + "completed" boolean NOT NULL, + "joined_at" timestamptz NOT NULL, + "amount_paid" decimal(10,2) NOT NULL, + "email" text, + "meta" jsonb, + "reference" uuid NOT NULL); SQL end @@ -50,7 +50,7 @@ describe Avram::Migrator::CreateTableStatement do built.statements.size.should eq 1 built.statements.first.should eq <<-SQL CREATE TABLE users ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid()); + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid()); SQL built = Avram::Migrator::CreateTableStatement.new(:users).build do @@ -60,7 +60,7 @@ describe Avram::Migrator::CreateTableStatement do built.statements.size.should eq 1 built.statements.first.should eq <<-SQL CREATE TABLE users ( - custom_id_name bigserial PRIMARY KEY); + "custom_id_name" bigserial PRIMARY KEY); SQL built = Avram::Migrator::CreateTableStatement.new(:users).build do @@ -70,7 +70,7 @@ describe Avram::Migrator::CreateTableStatement do built.statements.size.should eq 1 built.statements.first.should eq <<-SQL CREATE TABLE users ( - id smallserial PRIMARY KEY); + "id" smallserial PRIMARY KEY); SQL end @@ -84,9 +84,9 @@ describe Avram::Migrator::CreateTableStatement do built.statements.size.should eq 1 built.statements.first.should eq <<-SQL CREATE TABLE users ( - id1 bigint NOT NULL, - id2 uuid NOT NULL, - PRIMARY KEY (id1, id2)); + "id1" bigint NOT NULL, + "id2" uuid NOT NULL, + PRIMARY KEY ("id1", "id2")); SQL end @@ -102,10 +102,10 @@ describe Avram::Migrator::CreateTableStatement do built.statements.size.should eq 1 built.statements.first.should eq <<-SQL CREATE TABLE users ( - id1 bigint NOT NULL, - id2 uuid NOT NULL, - example text NOT NULL, - PRIMARY KEY (id1, id2)); + "id1" bigint NOT NULL, + "id2" uuid NOT NULL, + "example" text NOT NULL, + PRIMARY KEY ("id1", "id2")); SQL end @@ -128,18 +128,18 @@ describe Avram::Migrator::CreateTableStatement do built.statements.size.should eq 1 built.statements.first.should eq <<-SQL CREATE TABLE users ( - name text NOT NULL DEFAULT 'name', - email text DEFAULT 'optional', - age int4 NOT NULL DEFAULT '1', - num bigint NOT NULL DEFAULT '1', - amount_paid decimal NOT NULL DEFAULT '1.0', - completed boolean NOT NULL DEFAULT 'false', - meta jsonb NOT NULL DEFAULT '{}', - joined_at timestamptz NOT NULL DEFAULT NOW(), - future_time timestamptz NOT NULL DEFAULT '#{Time.local.to_utc}', - friend_count smallint NOT NULL DEFAULT '1', - friends text[] NOT NULL DEFAULT '{"Paul"}', - problems text[] NOT NULL DEFAULT '{}'); + "name" text NOT NULL DEFAULT 'name', + "email" text DEFAULT 'optional', + "age" int4 NOT NULL DEFAULT '1', + "num" bigint NOT NULL DEFAULT '1', + "amount_paid" decimal NOT NULL DEFAULT '1.0', + "completed" boolean NOT NULL DEFAULT 'false', + "meta" jsonb NOT NULL DEFAULT '{}', + "joined_at" timestamptz NOT NULL DEFAULT NOW(), + "future_time" timestamptz NOT NULL DEFAULT '#{Time.local.to_utc}', + "friend_count" smallint NOT NULL DEFAULT '1', + "friends" text[] NOT NULL DEFAULT '{"Paul"}', + "problems" text[] NOT NULL DEFAULT '{}'); SQL end @@ -156,13 +156,13 @@ describe Avram::Migrator::CreateTableStatement do built.statements.size.should eq 4 built.statements.first.should eq <<-SQL CREATE TABLE users ( - name text NOT NULL, - age int4 NOT NULL, - email text NOT NULL); + "name" text NOT NULL, + "age" int4 NOT NULL, + "email" text NOT NULL); SQL - built.statements[1].should eq "CREATE INDEX users_name_index ON users USING btree (name);" - built.statements[2].should eq "CREATE UNIQUE INDEX users_age_index ON users USING btree (age);" - built.statements[3].should eq "CREATE UNIQUE INDEX users_email_index ON users USING btree (email);" + built.statements[1].should eq %(CREATE INDEX users_name_index ON users USING btree ("name");) + built.statements[2].should eq %(CREATE UNIQUE INDEX users_age_index ON users USING btree ("age");) + built.statements[3].should eq %(CREATE UNIQUE INDEX users_email_index ON users USING btree ("email");) end it "raises error on columns with non allowed index types" do @@ -196,20 +196,20 @@ describe Avram::Migrator::CreateTableStatement do built.statements.first.should eq <<-SQL CREATE TABLE comments ( - user_id bigint NOT NULL REFERENCES users ON DELETE CASCADE, - post_id bigint REFERENCES posts ON DELETE RESTRICT, - category_label_id bigint NOT NULL REFERENCES custom_table ON DELETE SET NULL, - employee_id bigint NOT NULL REFERENCES users ON DELETE CASCADE, - line_item_id uuid NOT NULL REFERENCES line_items ON DELETE CASCADE, - subscription_item_id bigint NOT NULL REFERENCES subscription_items ON DELETE CASCADE); + "user_id" bigint NOT NULL REFERENCES users ON DELETE CASCADE, + "post_id" bigint REFERENCES posts ON DELETE RESTRICT, + "category_label_id" bigint NOT NULL REFERENCES custom_table ON DELETE SET NULL, + "employee_id" bigint NOT NULL REFERENCES users ON DELETE CASCADE, + "line_item_id" uuid NOT NULL REFERENCES line_items ON DELETE CASCADE, + "subscription_item_id" bigint NOT NULL REFERENCES subscription_items ON DELETE CASCADE); SQL - built.statements[1].should eq "CREATE INDEX comments_user_id_index ON comments USING btree (user_id);" - built.statements[2].should eq "CREATE INDEX comments_post_id_index ON comments USING btree (post_id);" - built.statements[3].should eq "CREATE INDEX comments_category_label_id_index ON comments USING btree (category_label_id);" - built.statements[4].should eq "CREATE INDEX comments_employee_id_index ON comments USING btree (employee_id);" - built.statements[5].should eq "CREATE INDEX comments_line_item_id_index ON comments USING btree (line_item_id);" - built.statements[6].should eq "CREATE INDEX comments_subscription_item_id_index ON comments USING btree (subscription_item_id);" + built.statements[1].should eq %(CREATE INDEX comments_user_id_index ON comments USING btree ("user_id");) + built.statements[2].should eq %(CREATE INDEX comments_post_id_index ON comments USING btree ("post_id");) + built.statements[3].should eq %(CREATE INDEX comments_category_label_id_index ON comments USING btree ("category_label_id");) + built.statements[4].should eq %(CREATE INDEX comments_employee_id_index ON comments USING btree ("employee_id");) + built.statements[5].should eq %(CREATE INDEX comments_line_item_id_index ON comments USING btree ("line_item_id");) + built.statements[6].should eq %(CREATE INDEX comments_subscription_item_id_index ON comments USING btree ("subscription_item_id");) end it "can create tables with association on composite primary keys" do @@ -222,9 +222,9 @@ describe Avram::Migrator::CreateTableStatement do built.statements.size.should eq 2 built.statements.first.should eq <<-SQL CREATE TABLE comments ( - user_id bigint NOT NULL REFERENCES users ON DELETE CASCADE, - id2 bigint NOT NULL, - PRIMARY KEY (user_id, id2)); + "user_id" bigint NOT NULL REFERENCES users ON DELETE CASCADE, + "id2" bigint NOT NULL, + PRIMARY KEY ("user_id", "id2")); SQL end @@ -242,7 +242,7 @@ describe Avram::Migrator::CreateTableStatement do add_belongs_to guest : User, on_delete: :cascade end - built.statements[1].should eq "CREATE INDEX challenges_guest_id_index ON challenges USING btree (guest_id);" + built.statements[1].should eq %(CREATE INDEX challenges_guest_id_index ON challenges USING btree ("guest_id");) built.statements.size.should eq(2) end end diff --git a/spec/avram/model_spec.cr b/spec/avram/model_spec.cr index 4aeb29fbe..8fa9a8cc2 100644 --- a/spec/avram/model_spec.cr +++ b/spec/avram/model_spec.cr @@ -8,7 +8,7 @@ class NamedSpaced::Model < BaseModel end private class QueryMe < BaseModel - COLUMN_SQL = "users.id, users.created_at, users.updated_at, users.email, users.age" + COLUMN_SQL = %("users"."id", "users"."created_at", "users"."updated_at", "users"."email", "users"."age") table :users do column email : CustomEmail @@ -22,7 +22,7 @@ private class EmptyModelCompilesOk < BaseModel end private class InferredTableNameModel < BaseModel - COLUMN_SQL = "inferred_table_name_models.id, inferred_table_name_models.created_at, inferred_table_name_models.updated_at" + COLUMN_SQL = %("inferred_table_name_models"."id", "inferred_table_name_models"."created_at", "inferred_table_name_models"."updated_at") table do end @@ -92,7 +92,7 @@ describe Avram::Model do end it "allows columns named the same as reserved SQL names" do - NoteFactory.create(&.from("Me").text("hi").read(true)) + NoteFactory.create(&.from("Me").text("hi").read(true).order(4)) note = NoteQuery.new.from("Me").first note.from.should eq("Me") note.text.should eq("hi") @@ -131,25 +131,25 @@ describe Avram::Model do it "sets up simple methods for equality" do query = QueryMe::BaseQuery.new.email("foo@bar.com").age(30) - query.to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE users.email = $1 AND users.age = $2", "foo@bar.com", "30"] + query.to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE "users"."email" = $1 AND "users"."age" = $2), "foo@bar.com", "30"] end it "sets up advanced criteria methods" do query = QueryMe::BaseQuery.new.email.upper.eq("foo@bar.com").age.gt(30) - query.to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE UPPER(users.email) = $1 AND users.age > $2", "foo@bar.com", "30"] + query.to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE UPPER("users"."email") = $1 AND "users"."age" > $2), "foo@bar.com", "30"] end it "parses values" do query = QueryMe::BaseQuery.new.email.upper.eq(" Foo@bar.com").age.gt(30) - query.to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE UPPER(users.email) = $1 AND users.age > $2", "foo@bar.com", "30"] + query.to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE UPPER("users"."email") = $1 AND "users"."age" > $2), "foo@bar.com", "30"] end it "lets you order by columns" do query = QueryMe::BaseQuery.new.age.asc_order.email.desc_order - query.to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users ORDER BY users.age ASC, users.email DESC"] + query.to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users ORDER BY "users"."age" ASC, "users"."email" DESC)] end it "can be deleted" do diff --git a/spec/avram/query_builder/merge_spec.cr b/spec/avram/query_builder/merge_spec.cr index c6ef4dbd4..c04d8de56 100644 --- a/spec/avram/query_builder/merge_spec.cr +++ b/spec/avram/query_builder/merge_spec.cr @@ -13,7 +13,7 @@ describe "Avram::QueryBuilder#merge" do query_1.merge(query_2) - query_1.statement.should eq "SELECT * FROM users INNER JOIN posts ON users.id = posts.user_id INNER JOIN tasks ON users.id = tasks.user_id WHERE age = $1 AND name = 'Mary' AND age = $2 AND name = 'Greg'" + query_1.statement.should eq %(SELECT * FROM users INNER JOIN posts ON "users"."id" = "posts"."user_id" INNER JOIN tasks ON "users"."id" = "tasks"."user_id" WHERE age = $1 AND name = 'Mary' AND age = $2 AND name = 'Greg') query_1.args.should eq ["42", "20"] end diff --git a/spec/avram/query_builder_spec.cr b/spec/avram/query_builder_spec.cr index a9ae98a72..1afbe5877 100644 --- a/spec/avram/query_builder_spec.cr +++ b/spec/avram/query_builder_spec.cr @@ -9,7 +9,7 @@ describe Avram::QueryBuilder do .order_by(Avram::OrderBy.new(:my_column, :asc)) query.joins.size.should eq(1) - query.statement.should eq "SELECT * FROM users INNER JOIN posts ON users.id = posts.user_id ORDER BY my_column ASC" + query.statement.should eq %(SELECT * FROM users INNER JOIN posts ON "users"."id" = "posts"."user_id" ORDER BY my_column ASC) end it "does not remove potentially duplicate where clauses" do @@ -239,7 +239,7 @@ describe Avram::QueryBuilder do it "specifies columns to be selected" do query = new_query.select([:name, :age]) - query.statement.should eq "SELECT users.name, users.age FROM users" + query.statement.should eq %(SELECT "users"."name", "users"."age" FROM users) end end @@ -248,7 +248,7 @@ describe Avram::QueryBuilder do .join(Avram::Join::Inner.new(:users, :posts)) .limit(1) - query.statement.should eq "SELECT * FROM users INNER JOIN posts ON users.id = posts.user_id LIMIT 1" + query.statement.should eq %(SELECT * FROM users INNER JOIN posts ON "users"."id" = "posts"."user_id" LIMIT 1) end describe "#reverse_order" do @@ -310,9 +310,9 @@ describe Avram::QueryBuilder do .limit(10) .offset(5) - cloned_query.statement.should eq "SELECT users.name, users.age FROM users INNER JOIN posts ON users.id = posts.user_id WHERE name = $1 AND age > $2 ORDER BY id ASC LIMIT 10 OFFSET 5" + cloned_query.statement.should eq %(SELECT "users"."name", "users"."age" FROM users INNER JOIN posts ON "users"."id" = "posts"."user_id" WHERE name = $1 AND age > $2 ORDER BY id ASC LIMIT 10 OFFSET 5) - old_query.statement.should eq "SELECT users.name, users.age FROM users INNER JOIN posts ON users.id = posts.user_id WHERE name = $1 ORDER BY id ASC LIMIT 1 OFFSET 2" + old_query.statement.should eq %(SELECT "users"."name", "users"."age" FROM users INNER JOIN posts ON "users"."id" = "posts"."user_id" WHERE name = $1 ORDER BY id ASC LIMIT 1 OFFSET 2) end end diff --git a/spec/avram/queryable_spec.cr b/spec/avram/queryable_spec.cr index 37a725526..3faa38704 100644 --- a/spec/avram/queryable_spec.cr +++ b/spec/avram/queryable_spec.cr @@ -53,13 +53,13 @@ describe Avram::Queryable do it "can set default queries" do query = QueryWithDefault.new.query - query.statement.should eq "SELECT #{User::COLUMN_SQL} FROM users WHERE users.age >= $1" + query.statement.should eq %(SELECT #{User::COLUMN_SQL} FROM users WHERE "users"."age" >= $1) end it "allows you to add on to a query with default" do query = QueryWithDefault.new.name("Santa").query - query.statement.should eq "SELECT #{User::COLUMN_SQL} FROM users WHERE users.age >= $1 AND users.name = $2" + query.statement.should eq %(SELECT #{User::COLUMN_SQL} FROM users WHERE "users"."age" >= $1 AND "users"."name" = $2) end it "releases connection if no open transaction", tags: Avram::SpecHelper::TRUNCATE do @@ -108,7 +108,7 @@ describe Avram::Queryable do it "resets where on a specific column" do query = UserQuery.new.name("Purcell").age(35).reset_where(&.name).query - query.statement.should eq "SELECT #{User::COLUMN_SQL} FROM users WHERE users.age = $1" + query.statement.should eq %(SELECT #{User::COLUMN_SQL} FROM users WHERE "users"."age" = $1) query.args.should eq ["35"] of String end @@ -131,7 +131,7 @@ describe Avram::Queryable do queryable = UserQuery.new.distinct_on(&.name).order_by(:name, :asc).order_by(:age, :asc) query = queryable.query - query.statement.should eq "SELECT DISTINCT ON (users.name) #{User::COLUMN_SQL} FROM users ORDER BY name ASC, age ASC" + query.statement.should eq %(SELECT DISTINCT ON ("users"."name") #{User::COLUMN_SQL} FROM users ORDER BY name ASC, age ASC) query.args.should eq [] of String results = queryable.results first = results.first @@ -207,7 +207,7 @@ describe Avram::Queryable do user.should_not be_nil user.as(User).name.should eq "First" - user_query.should eq "SELECT #{User::COLUMN_SQL} FROM users ORDER BY users.id ASC LIMIT 1" + user_query.should eq %(SELECT #{User::COLUMN_SQL} FROM users ORDER BY "users"."id" ASC LIMIT 1) end it "returns nil if no record found" do @@ -299,7 +299,7 @@ describe Avram::Queryable do user.should_not be_nil user.as(User).name.should eq "Last" - user_query.should eq "SELECT #{User::COLUMN_SQL} FROM users ORDER BY users.id DESC LIMIT 1" + user_query.should eq %(SELECT #{User::COLUMN_SQL} FROM users ORDER BY "users"."id" DESC LIMIT 1) end it "returns nil if last record is not found" do @@ -462,14 +462,14 @@ describe Avram::Queryable do it "chains ors" do query = UserQuery.new.age(26).or(&.age(32)).or(&.age(59)).query - query.statement.should eq "SELECT #{User::COLUMN_SQL} FROM users WHERE users.age = $1 OR users.age = $2 OR users.age = $3" + query.statement.should eq %(SELECT #{User::COLUMN_SQL} FROM users WHERE "users"."age" = $1 OR "users"."age" = $2 OR "users"."age" = $3) query.args.should eq ["26", "32", "59"] end it "nests AND conjunctions inside of OR blocks" do query = UserQuery.new.age(26).or(&.age(32).name("Pat")).or(&.age(59)).query - query.statement.should eq "SELECT #{User::COLUMN_SQL} FROM users WHERE users.age = $1 OR users.age = $2 AND users.name = $3 OR users.age = $4" + query.statement.should eq %(SELECT #{User::COLUMN_SQL} FROM users WHERE "users"."age" = $1 OR "users"."age" = $2 AND "users"."name" = $3 OR "users"."age" = $4) query.args.should eq ["26", "32", "Pat", "59"] end end @@ -478,7 +478,7 @@ describe Avram::Queryable do it "wraps a simple where clause with parenthesis" do query = UserQuery.new.where(&.age(30)).query - query.statement.should eq "SELECT #{User::COLUMN_SQL} FROM users WHERE ( users.age = $1 )" + query.statement.should eq %(SELECT #{User::COLUMN_SQL} FROM users WHERE ( "users"."age" = $1 )) query.args.should eq ["30"] end @@ -493,7 +493,7 @@ describe Avram::Queryable do q.nickname("Strange") }.query - query.statement.should eq "SELECT #{User::COLUMN_SQL} FROM users WHERE ( ( users.age = $1 OR users.age = $2 ) AND ( users.name = $3 OR users.name = $4 ) ) OR users.nickname = $5" + query.statement.should eq %(SELECT #{User::COLUMN_SQL} FROM users WHERE ( ( "users"."age" = $1 OR "users"."age" = $2 ) AND ( "users"."name" = $3 OR "users"."name" = $4 ) ) OR "users"."nickname" = $5) query.args.should eq ["25", "26", "Billy", "Tommy", "Strange"] end @@ -503,7 +503,7 @@ describe Avram::Queryable do new_query = orig_query.where(&.nickname("BusyCat")).limit(3) orig_query.query.statement.should eq "SELECT #{User::COLUMN_SQL} FROM users" - new_query.query.statement.should eq "SELECT #{User::COLUMN_SQL} FROM users WHERE ( users.nickname = $1 ) LIMIT 3" + new_query.query.statement.should eq %(SELECT #{User::COLUMN_SQL} FROM users WHERE ( "users"."nickname" = $1 ) LIMIT 3) end it "doesn't add parenthesis when query to wrap is provided" do @@ -516,7 +516,7 @@ describe Avram::Queryable do end end.age(25).query - query.statement.should eq "SELECT #{User::COLUMN_SQL} FROM users WHERE users.name = $1 AND users.age = $2" + query.statement.should eq %(SELECT #{User::COLUMN_SQL} FROM users WHERE "users"."name" = $1 AND "users"."age" = $2) query.args.should eq ["Susan", "25"] end end @@ -533,7 +533,7 @@ describe Avram::Queryable do UserFactory.create users = UserQuery.new.name.desc_order.limit(1) - users.query.statement.should eq "SELECT #{User::COLUMN_SQL} FROM users ORDER BY users.name DESC LIMIT 1" + users.query.statement.should eq %(SELECT #{User::COLUMN_SQL} FROM users ORDER BY "users"."name" DESC LIMIT 1) users.results.size.should eq(1) end @@ -1061,7 +1061,7 @@ describe Avram::Queryable do CommentFactory.new.post_id(post.id).create query = Comment::BaseQuery.new.join_post - query.to_sql.should eq ["SELECT comments.custom_id, comments.created_at, comments.updated_at, comments.body, comments.post_id FROM comments INNER JOIN posts ON comments.post_id = posts.custom_id"] + query.to_sql.should eq [%(SELECT #{Comment::COLUMN_SQL} FROM comments INNER JOIN posts ON "comments"."post_id" = "posts"."custom_id")] result = query.first result.post.should eq post @@ -1081,7 +1081,7 @@ describe Avram::Queryable do comment = CommentFactory.new.post_id(post.id).create query = Post::BaseQuery.new.join_comments - query.to_sql.should eq ["SELECT posts.custom_id, posts.created_at, posts.updated_at, posts.title, posts.published_at FROM posts INNER JOIN comments ON posts.custom_id = comments.post_id"] + query.to_sql.should eq [%(SELECT #{Post::COLUMN_SQL} FROM posts INNER JOIN comments ON "posts"."custom_id" = "comments"."post_id")] result = query.first result.comments.first.should eq comment @@ -1102,7 +1102,7 @@ describe Avram::Queryable do TaggingFactory.new.post_id(post.id).tag_id(tag.id).create query = Post::BaseQuery.new.join_tags - query.to_sql.should eq ["SELECT posts.custom_id, posts.created_at, posts.updated_at, posts.title, posts.published_at FROM posts INNER JOIN taggings ON posts.custom_id = taggings.post_id INNER JOIN tags ON taggings.tag_id = tags.custom_id"] + query.to_sql.should eq [%(SELECT #{Post::COLUMN_SQL} FROM posts INNER JOIN taggings ON "posts"."custom_id" = "taggings"."post_id" INNER JOIN tags ON "taggings"."tag_id" = "tags"."custom_id")] result = query.first result.tags.first.should eq tag @@ -1123,7 +1123,7 @@ describe Avram::Queryable do employee = EmployeeFactory.create query = Employee::BaseQuery.new.left_join_manager - query.to_sql.should eq ["SELECT employees.id, employees.created_at, employees.updated_at, employees.name, employees.manager_id FROM employees LEFT JOIN managers ON employees.manager_id = managers.id"] + query.to_sql.should eq [%(SELECT #{Employee::COLUMN_SQL} FROM employees LEFT JOIN managers ON "employees"."manager_id" = "managers"."id")] result = query.first result.should eq employee @@ -1142,7 +1142,7 @@ describe Avram::Queryable do post = PostFactory.create query = Post::BaseQuery.new.left_join_comments - query.to_sql.should eq ["SELECT posts.custom_id, posts.created_at, posts.updated_at, posts.title, posts.published_at FROM posts LEFT JOIN comments ON posts.custom_id = comments.post_id"] + query.to_sql.should eq [%(SELECT #{Post::COLUMN_SQL} FROM posts LEFT JOIN comments ON "posts"."custom_id" = "comments"."post_id")] result = query.first result.should eq post @@ -1161,7 +1161,7 @@ describe Avram::Queryable do post = PostFactory.create query = Post::BaseQuery.new.left_join_tags - query.to_sql.should eq ["SELECT posts.custom_id, posts.created_at, posts.updated_at, posts.title, posts.published_at FROM posts LEFT JOIN taggings ON posts.custom_id = taggings.post_id LEFT JOIN tags ON taggings.tag_id = tags.custom_id"] + query.to_sql.should eq [%(SELECT #{Post::COLUMN_SQL} FROM posts LEFT JOIN taggings ON "posts"."custom_id" = "taggings"."post_id" LEFT JOIN tags ON "taggings"."tag_id" = "tags"."custom_id")] result = query.first result.should eq post @@ -1183,17 +1183,17 @@ describe Avram::Queryable do blob = BlobFactory.new.doc(JSON::Any.new({"foo" => JSON::Any.new("bar")})).create query = JSONQuery.new.static_foo - query.to_sql.should eq ["SELECT blobs.id, blobs.created_at, blobs.updated_at, blobs.doc, blobs.metadata, blobs.media, blobs.servers FROM blobs WHERE blobs.doc = $1", "{\"foo\":\"bar\"}"] + query.to_sql.should eq [%(SELECT #{Blob::COLUMN_SQL} FROM blobs WHERE "blobs"."doc" = $1), %({"foo":"bar"})] result = query.first result.should eq blob query2 = JSONQuery.new.foo_with_value("bar") - query2.to_sql.should eq ["SELECT blobs.id, blobs.created_at, blobs.updated_at, blobs.doc, blobs.metadata, blobs.media, blobs.servers FROM blobs WHERE blobs.doc = $1", "{\"foo\":\"bar\"}"] + query2.to_sql.should eq [%(SELECT #{Blob::COLUMN_SQL} FROM blobs WHERE "blobs"."doc" = $1), %({"foo":"bar"})] result = query2.first result.should eq blob query3 = JSONQuery.new.foo_with_value("baz") - query3.to_sql.should eq ["SELECT blobs.id, blobs.created_at, blobs.updated_at, blobs.doc, blobs.metadata, blobs.media, blobs.servers FROM blobs WHERE blobs.doc = $1", "{\"foo\":\"baz\"}"] + query3.to_sql.should eq [%(SELECT #{Blob::COLUMN_SQL} FROM blobs WHERE "blobs"."doc" = $1), %({"foo":"baz"})] expect_raises(Avram::RecordNotFoundError) do query3.first end @@ -1207,7 +1207,7 @@ describe Avram::Queryable do bucket = BucketFactory.new.names(["pumpkin", "zucchini"]).enums([Bucket::Size::Medium]).create query = BucketQuery.new.names(["pumpkin", "zucchini"]) - query.to_sql.should eq ["SELECT #{Bucket::COLUMN_SQL} FROM buckets WHERE buckets.names = $1", "{\"pumpkin\",\"zucchini\"}"] + query.to_sql.should eq [%(SELECT #{Bucket::COLUMN_SQL} FROM buckets WHERE "buckets"."names" = $1), %({"pumpkin","zucchini"})] result = query.first result.should eq bucket @@ -1222,7 +1222,7 @@ describe Avram::Queryable do query = BucketQuery.new.numbers.includes(13) - query.to_sql.should eq ["SELECT #{Bucket::COLUMN_SQL} FROM buckets WHERE $1 = ANY (buckets.numbers)", "13"] + query.to_sql.should eq [%(SELECT #{Bucket::COLUMN_SQL} FROM buckets WHERE $1 = ANY ("buckets"."numbers")), "13"] query.select_count.should eq(1) query.first.id.should eq(bucket1.id) end @@ -1233,7 +1233,7 @@ describe Avram::Queryable do query = BucketQuery.new.numbers.not.includes(13) - query.to_sql.should eq ["SELECT #{Bucket::COLUMN_SQL} FROM buckets WHERE $1 != ALL (buckets.numbers)", "13"] + query.to_sql.should eq [%(SELECT #{Bucket::COLUMN_SQL} FROM buckets WHERE $1 != ALL ("buckets"."numbers")), "13"] query.select_count.should eq(1) query.first.id.should eq(bucket2.id) end @@ -1246,7 +1246,7 @@ describe Avram::Queryable do business = BusinessFactory.new.create query = BusinessQuery.new.name(business.name) - query.to_sql.should eq ["SELECT #{Business::COLUMN_SQL} FROM businesses WHERE businesses.name = $1", business.name] + query.to_sql.should eq [%(SELECT #{Business::COLUMN_SQL} FROM businesses WHERE "businesses"."name" = $1), business.name] result = query.first result.should eq business end @@ -1401,19 +1401,19 @@ describe Avram::Queryable do describe "#asc_order" do it "orders by a joined table" do query = Post::BaseQuery.new.where_comments(Comment::BaseQuery.new.created_at.asc_order) - query.to_sql[0].should contain "ORDER BY comments.created_at ASC" + query.to_sql[0].should contain %(ORDER BY "comments"."created_at" ASC) end it "orders nulls first" do query = Post::BaseQuery.new.published_at.asc_order(:nulls_first) - query.to_sql[0].should contain "ORDER BY posts.published_at ASC NULLS FIRST" + query.to_sql[0].should contain %(ORDER BY "posts"."published_at" ASC NULLS FIRST) end it "orders nulls last" do query = Post::BaseQuery.new.published_at.asc_order(:nulls_last) - query.to_sql[0].should contain "ORDER BY posts.published_at ASC NULLS LAST" + query.to_sql[0].should contain %(ORDER BY "posts"."published_at" ASC NULLS LAST) end it "doesn't mutate the query" do @@ -1428,7 +1428,7 @@ describe Avram::Queryable do it "resets random order clauses" do query = Post::BaseQuery.new.random_order.published_at.asc_order - query.to_sql[0].should contain "ORDER BY posts.published_at ASC" + query.to_sql[0].should contain %(ORDER BY "posts"."published_at" ASC) query.to_sql[0].should_not contain "RANDOM ()" end end @@ -1443,7 +1443,7 @@ describe Avram::Queryable do it "resets previous order clauses" do query = Post::BaseQuery.new.published_at.desc_order.random_order - query.to_sql[0].should_not contain "posts.published_at DESC" + query.to_sql[0].should_not contain %("posts"."published_at" DESC) query.to_sql[0].should contain "ORDER BY RANDOM ()" end end @@ -1455,7 +1455,7 @@ describe Avram::Queryable do original_query.to_sql.size.should eq 2 new_query.to_sql.size.should eq 3 - new_query.to_sql[0].should contain "ORDER BY users.joined_at" + new_query.to_sql[0].should contain %(ORDER BY "users"."joined_at") original_query.to_sql[0].should_not contain "ORDER BY" end @@ -1524,7 +1524,7 @@ describe Avram::Queryable do post = PostFactory.create &.published_at(3.days.ago) posts = Post::BaseQuery.new.published_at.between(start_date, end_date) - posts.query.statement.should eq "SELECT posts.custom_id, posts.created_at, posts.updated_at, posts.title, posts.published_at FROM posts WHERE posts.published_at >= $1 AND posts.published_at <= $2" + posts.query.statement.should eq %(SELECT #{Post::COLUMN_SQL} FROM posts WHERE "posts"."published_at" >= $1 AND "posts"."published_at" <= $2) posts.query.args.should eq [start_date.to_s("%Y-%m-%d %H:%M:%S.%6N %z"), end_date.to_s("%Y-%m-%d %H:%M:%S.%6N %z")] posts.first.should eq post end @@ -1533,7 +1533,7 @@ describe Avram::Queryable do company = CompanyFactory.create &.sales(50) companies = Company::BaseQuery.new.sales.between(1, 100) - companies.query.statement.should eq "SELECT companies.id, companies.created_at, companies.updated_at, companies.sales, companies.earnings FROM companies WHERE companies.sales >= $1 AND companies.sales <= $2" + companies.query.statement.should eq %(SELECT #{Company::COLUMN_SQL} FROM companies WHERE "companies"."sales" >= $1 AND "companies"."sales" <= $2) companies.query.args.should eq ["1", "100"] companies.first.should eq company end @@ -1542,7 +1542,7 @@ describe Avram::Queryable do company = CompanyFactory.create &.earnings(300.45) companies = Company::BaseQuery.new.earnings.between(123.45, 678.901) - companies.query.statement.should eq "SELECT companies.id, companies.created_at, companies.updated_at, companies.sales, companies.earnings FROM companies WHERE companies.earnings >= $1 AND companies.earnings <= $2" + companies.query.statement.should eq %(SELECT #{Company::COLUMN_SQL} FROM companies WHERE "companies"."earnings" >= $1 AND "companies"."earnings" <= $2) companies.query.args.should eq ["123.45", "678.901"] companies.first.should eq company end @@ -1564,7 +1564,7 @@ describe Avram::Queryable do UserFactory.create &.age(21).name("Jim") users = UserQuery.new.group(&.age).group(&.id) - users.query.statement.should eq "SELECT #{User::COLUMN_SQL} FROM users GROUP BY users.age, users.id" + users.query.statement.should eq %(SELECT #{User::COLUMN_SQL} FROM users GROUP BY "users"."age", "users"."id") users.map(&.name).sort!.should eq ["Dwight", "Jim", "Michael"] end @@ -1611,16 +1611,16 @@ describe Avram::Queryable do describe "#to_prepared_sql" do it "returns the full SQL with args combined" do query = Post::BaseQuery.new.title("The Short Post") - query.to_prepared_sql.should eq(%{SELECT posts.custom_id, posts.created_at, posts.updated_at, posts.title, posts.published_at FROM posts WHERE posts.title = 'The Short Post'}) + query.to_prepared_sql.should eq(%{SELECT #{Post::COLUMN_SQL} FROM posts WHERE "posts"."title" = 'The Short Post'}) query = Bucket::BaseQuery.new.names(["Larry", "Moe", "Curly"]).numbers([1, 2, 3]) - query.to_prepared_sql.should eq(%{SELECT #{Bucket::COLUMN_SQL} FROM buckets WHERE buckets.names = '{"Larry","Moe","Curly"}' AND buckets.numbers = '{1,2,3}'}) + query.to_prepared_sql.should eq(%{SELECT #{Bucket::COLUMN_SQL} FROM buckets WHERE "buckets"."names" = '{"Larry","Moe","Curly"}' AND "buckets"."numbers" = '{1,2,3}'}) query = Blob::BaseQuery.new.doc(JSON::Any.new({"properties" => JSON::Any.new("sold")})) - query.to_prepared_sql.should eq(%{SELECT blobs.id, blobs.created_at, blobs.updated_at, blobs.doc, blobs.metadata, blobs.media, blobs.servers FROM blobs WHERE blobs.doc = '{"properties":"sold"}'}) + query.to_prepared_sql.should eq(%{SELECT #{Blob::COLUMN_SQL} FROM blobs WHERE "blobs"."doc" = '{"properties":"sold"}'}) query = UserQuery.new.name.in(["Don", "Juan"]).age.gt(30) - query.to_prepared_sql.should eq(%{SELECT #{User::COLUMN_SQL} FROM users WHERE users.name = ANY ('{"Don","Juan"}') AND users.age > '30'}) + query.to_prepared_sql.should eq(%{SELECT #{User::COLUMN_SQL} FROM users WHERE "users"."name" = ANY ('{"Don","Juan"}') AND "users"."age" > '30'}) end it "returns the full SQL with a lot of args" do @@ -1641,7 +1641,7 @@ describe Avram::Queryable do .available_for_hire(true) .created_at(a_day) - query.to_prepared_sql.should eq(%{SELECT users.id, users.created_at, users.updated_at, users.name, users.age, users.year_born, users.nickname, users.joined_at, users.total_score, users.average_score, users.available_for_hire FROM users WHERE users.name = 'Don' AND users.age > '21' AND users.age < '99' AND users.nickname ILIKE 'j%' AND users.nickname ILIKE '%y' AND users.joined_at > '#{a_week.to_s("%F %X.%6N %z")}' AND users.joined_at < '#{an_hour.to_s("%F %X.%6N %z")}' AND users.average_score > '1.2' AND users.average_score < '4.9' AND users.available_for_hire = 'true' AND users.created_at = '#{a_day.to_s("%F %X.%6N %z")}'}) + query.to_prepared_sql.should eq(%{SELECT #{User::COLUMN_SQL} FROM users WHERE "users"."name" = 'Don' AND "users"."age" > '21' AND "users"."age" < '99' AND "users"."nickname" ILIKE 'j%' AND "users"."nickname" ILIKE '%y' AND "users"."joined_at" > '#{a_week.to_s("%F %X.%6N %z")}' AND "users"."joined_at" < '#{an_hour.to_s("%F %X.%6N %z")}' AND "users"."average_score" > '1.2' AND "users"."average_score" < '4.9' AND "users"."available_for_hire" = 'true' AND "users"."created_at" = '#{a_day.to_s("%F %X.%6N %z")}'}) end end diff --git a/spec/avram/string_criteria_spec.cr b/spec/avram/string_criteria_spec.cr index a79705a81..ad6fdfa28 100644 --- a/spec/avram/string_criteria_spec.cr +++ b/spec/avram/string_criteria_spec.cr @@ -1,7 +1,7 @@ require "../spec_helper" private class QueryMe < BaseModel - COLUMN_SQL = "users.id, users.created_at, users.updated_at, users.name" + COLUMN_SQL = %("users"."id", "users"."created_at", "users"."updated_at", "users"."name") table users do column name : String @@ -11,63 +11,63 @@ end describe String::Lucky::Criteria do describe "like" do it "uses LIKE" do - name.like("elon").to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE users.name LIKE $1", "elon"] + name.like("elon").to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE "users"."name" LIKE $1), "elon"] end end describe "ilike" do it "uses LIKE" do - name.ilike("elon").to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE users.name ILIKE $1", "elon"] + name.ilike("elon").to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE "users"."name" ILIKE $1), "elon"] end end describe "lower" do it "uses LOWER" do - name.lower.eq("elon").to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE LOWER(users.name) = $1", "elon"] + name.lower.eq("elon").to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE LOWER("users"."name") = $1), "elon"] end end describe "upper" do it "uses UPPER" do - name.upper.eq("elon").to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE UPPER(users.name) = $1", "elon"] + name.upper.eq("elon").to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE UPPER("users"."name") = $1), "elon"] end end describe "trim" do it "uses TRIM" do - name.trim.eq("elon").to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE TRIM(users.name) = $1", "elon"] + name.trim.eq("elon").to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE TRIM("users"."name") = $1), "elon"] end end describe "not" do describe "with chained criteria" do it "negates the following criteria" do - name.not.like("pete").to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE users.name NOT LIKE $1", "pete"] - name.not.ilike("pete").to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE users.name NOT ILIKE $1", "pete"] + name.not.like("pete").to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE "users"."name" NOT LIKE $1), "pete"] + name.not.ilike("pete").to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE "users"."name" NOT ILIKE $1), "pete"] end it "resets after having negated once" do - name.not.like("pete").name.eq("sarah").to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE users.name NOT LIKE $1 AND users.name = $2", "pete", "sarah"] - name.not.ilike("pete").name.eq("sarah").to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE users.name NOT ILIKE $1 AND users.name = $2", "pete", "sarah"] + name.not.like("pete").name.eq("sarah").to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE "users"."name" NOT LIKE $1 AND "users"."name" = $2), "pete", "sarah"] + name.not.ilike("pete").name.eq("sarah").to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE "users"."name" NOT ILIKE $1 AND "users"."name" = $2), "pete", "sarah"] end end end describe "length" do it "uses LENGTH" do - name.length.eq(4).to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE LENGTH(users.name) = $1", "4"] + name.length.eq(4).to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE LENGTH("users"."name") = $1), "4"] end end describe "reverse" do it "uses REVERSE" do - name.reverse.eq("revir").to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE REVERSE(users.name) = $1", "revir"] + name.reverse.eq("revir").to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE REVERSE("users"."name") = $1), "revir"] end end describe "match" do it "uses @@" do - name.to_tsvector.match("jeb").to_sql.should eq ["SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE TO_TSVECTOR(users.name) @@ TO_TSQUERY($1)", "jeb"] + name.to_tsvector.match("jeb").to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE TO_TSVECTOR("users"."name") @@ TO_TSQUERY($1)), "jeb"] end end end diff --git a/spec/avram/time_criteria_spec.cr b/spec/avram/time_criteria_spec.cr index 13074e1e0..a8995ca43 100644 --- a/spec/avram/time_criteria_spec.cr +++ b/spec/avram/time_criteria_spec.cr @@ -1,6 +1,7 @@ require "../spec_helper" private class QueryMe < BaseModel + COLUMN_SQL = %("users"."id", "users"."created_at", "users"."updated_at", "users"."activated_at") table users do column activated_at : Time end @@ -10,13 +11,13 @@ describe Time::Lucky::Criteria do describe "is" do it "=" do now = Time.utc - activated_at.eq(now).to_sql.should eq ["SELECT users.id, users.created_at, users.updated_at, users.activated_at FROM users WHERE users.activated_at = $1", now.to_s("%F %X.%6N %z")] + activated_at.eq(now).to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE "users"."activated_at" = $1), now.to_s("%F %X.%6N %z")] end end it "as_date" do input_date = "2012-01-31" - activated_at.as_date.eq(input_date).to_sql.should eq ["SELECT users.id, users.created_at, users.updated_at, users.activated_at FROM users WHERE DATE(users.activated_at) = $1", input_date] + activated_at.as_date.eq(input_date).to_sql.should eq [%(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE DATE("users"."activated_at") = $1), input_date] end describe "extract" do @@ -26,126 +27,126 @@ describe Time::Lucky::Criteria do describe "returning integer" do it "century" do - output_query = "SELECT users.id, users.created_at, users.updated_at, users.activated_at FROM users WHERE extract(century from users.activated_at) = $1" + output_query = %(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE extract(century from "users"."activated_at") = $1) activated_at.extract(Avram::ChronoUnits::Century).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract(:century).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract_century.eq(5).to_sql.should eq [output_query, "5"] end it "day" do - output_query = "SELECT users.id, users.created_at, users.updated_at, users.activated_at FROM users WHERE extract(day from users.activated_at) = $1" + output_query = %(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE extract(day from "users"."activated_at") = $1) activated_at.extract(Avram::ChronoUnits::Day).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract(:day).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract_day.eq(5).to_sql.should eq [output_query, "5"] end it "decade" do - output_query = "SELECT users.id, users.created_at, users.updated_at, users.activated_at FROM users WHERE extract(decade from users.activated_at) = $1" + output_query = %(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE extract(decade from "users"."activated_at") = $1) activated_at.extract(Avram::ChronoUnits::Decade).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract(:decade).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract_decade.eq(5).to_sql.should eq [output_query, "5"] end it "dow" do - output_query = "SELECT users.id, users.created_at, users.updated_at, users.activated_at FROM users WHERE extract(dow from users.activated_at) = $1" + output_query = %(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE extract(dow from "users"."activated_at") = $1) activated_at.extract(Avram::ChronoUnits::Dow).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract(:dow).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract_dow.eq(5).to_sql.should eq [output_query, "5"] end it "doy" do - output_query = "SELECT users.id, users.created_at, users.updated_at, users.activated_at FROM users WHERE extract(doy from users.activated_at) = $1" + output_query = %(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE extract(doy from "users"."activated_at") = $1) activated_at.extract(Avram::ChronoUnits::Doy).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract(:doy).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract_doy.eq(5).to_sql.should eq [output_query, "5"] end it "hour" do - output_query = "SELECT users.id, users.created_at, users.updated_at, users.activated_at FROM users WHERE extract(hour from users.activated_at) = $1" + output_query = %(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE extract(hour from "users"."activated_at") = $1) activated_at.extract(Avram::ChronoUnits::Hour).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract(:hour).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract_hour.eq(5).to_sql.should eq [output_query, "5"] end it "isodow" do - output_query = "SELECT users.id, users.created_at, users.updated_at, users.activated_at FROM users WHERE extract(isodow from users.activated_at) = $1" + output_query = %(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE extract(isodow from "users"."activated_at") = $1) activated_at.extract(Avram::ChronoUnits::Isodow).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract(:isodow).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract_isodow.eq(5).to_sql.should eq [output_query, "5"] end it "isoyear" do - output_query = "SELECT users.id, users.created_at, users.updated_at, users.activated_at FROM users WHERE extract(isoyear from users.activated_at) = $1" + output_query = %(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE extract(isoyear from "users"."activated_at") = $1) activated_at.extract(Avram::ChronoUnits::Isoyear).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract(:isoyear).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract_isoyear.eq(5).to_sql.should eq [output_query, "5"] end it "microseconds" do - output_query = "SELECT users.id, users.created_at, users.updated_at, users.activated_at FROM users WHERE extract(microseconds from users.activated_at) = $1" + output_query = %(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE extract(microseconds from "users"."activated_at") = $1) activated_at.extract(Avram::ChronoUnits::Microseconds).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract(:microseconds).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract_microseconds.eq(5).to_sql.should eq [output_query, "5"] end it "millennium" do - output_query = "SELECT users.id, users.created_at, users.updated_at, users.activated_at FROM users WHERE extract(millennium from users.activated_at) = $1" + output_query = %(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE extract(millennium from "users"."activated_at") = $1) activated_at.extract(Avram::ChronoUnits::Millennium).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract(:millennium).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract_millennium.eq(5).to_sql.should eq [output_query, "5"] end it "minute" do - output_query = "SELECT users.id, users.created_at, users.updated_at, users.activated_at FROM users WHERE extract(minute from users.activated_at) = $1" + output_query = %(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE extract(minute from "users"."activated_at") = $1) activated_at.extract(Avram::ChronoUnits::Minute).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract(:minute).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract_minute.eq(5).to_sql.should eq [output_query, "5"] end it "month" do - output_query = "SELECT users.id, users.created_at, users.updated_at, users.activated_at FROM users WHERE extract(month from users.activated_at) = $1" + output_query = %(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE extract(month from "users"."activated_at") = $1) activated_at.extract(Avram::ChronoUnits::Month).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract(:month).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract_month.eq(5).to_sql.should eq [output_query, "5"] end it "quarter" do - output_query = "SELECT users.id, users.created_at, users.updated_at, users.activated_at FROM users WHERE extract(quarter from users.activated_at) = $1" + output_query = %(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE extract(quarter from "users"."activated_at") = $1) activated_at.extract(Avram::ChronoUnits::Quarter).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract(:quarter).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract_quarter.eq(5).to_sql.should eq [output_query, "5"] end it "timezone" do - output_query = "SELECT users.id, users.created_at, users.updated_at, users.activated_at FROM users WHERE extract(timezone from users.activated_at) = $1" + output_query = %(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE extract(timezone from "users"."activated_at") = $1) activated_at.extract(Avram::ChronoUnits::Timezone).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract(:timezone).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract_timezone.eq(5).to_sql.should eq [output_query, "5"] end it "timezone_hour" do - output_query = "SELECT users.id, users.created_at, users.updated_at, users.activated_at FROM users WHERE extract(timezone_hour from users.activated_at) = $1" + output_query = %(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE extract(timezone_hour from "users"."activated_at") = $1) activated_at.extract(Avram::ChronoUnits::TimezoneHour).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract(:timezone_hour).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract_timezone_hour.eq(5).to_sql.should eq [output_query, "5"] end it "timezone_minute" do - output_query = "SELECT users.id, users.created_at, users.updated_at, users.activated_at FROM users WHERE extract(timezone_minute from users.activated_at) = $1" + output_query = %(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE extract(timezone_minute from "users"."activated_at") = $1) activated_at.extract(Avram::ChronoUnits::TimezoneMinute).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract(:timezone_minute).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract_timezone_minute.eq(5).to_sql.should eq [output_query, "5"] end it "week" do - output_query = "SELECT users.id, users.created_at, users.updated_at, users.activated_at FROM users WHERE extract(week from users.activated_at) = $1" + output_query = %(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE extract(week from "users"."activated_at") = $1) activated_at.extract(Avram::ChronoUnits::Week).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract(:week).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract_week.eq(5).to_sql.should eq [output_query, "5"] end it "year" do - output_query = "SELECT users.id, users.created_at, users.updated_at, users.activated_at FROM users WHERE extract(year from users.activated_at) = $1" + output_query = %(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE extract(year from "users"."activated_at") = $1) activated_at.extract(Avram::ChronoUnits::Year).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract(:year).eq(5).to_sql.should eq [output_query, "5"] activated_at.extract_year.eq(5).to_sql.should eq [output_query, "5"] @@ -154,28 +155,28 @@ describe Time::Lucky::Criteria do describe "returning float" do it "epoch" do - output_query = "SELECT users.id, users.created_at, users.updated_at, users.activated_at FROM users WHERE extract(epoch from users.activated_at) = $1" + output_query = %(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE extract(epoch from "users"."activated_at") = $1) activated_at.extract(Avram::ChronoUnits::Epoch).eq(5).to_sql.should eq [output_query, "5.0"] activated_at.extract(:epoch).eq(5).to_sql.should eq [output_query, "5.0"] activated_at.extract_epoch.eq(5).to_sql.should eq [output_query, "5.0"] end it "julian" do - output_query = "SELECT users.id, users.created_at, users.updated_at, users.activated_at FROM users WHERE extract(julian from users.activated_at) = $1" + output_query = %(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE extract(julian from "users"."activated_at") = $1) activated_at.extract(Avram::ChronoUnits::Julian).eq(5).to_sql.should eq [output_query, "5.0"] activated_at.extract(:julian).eq(5).to_sql.should eq [output_query, "5.0"] activated_at.extract_julian.eq(5).to_sql.should eq [output_query, "5.0"] end it "milliseconds" do - output_query = "SELECT users.id, users.created_at, users.updated_at, users.activated_at FROM users WHERE extract(milliseconds from users.activated_at) = $1" + output_query = %(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE extract(milliseconds from "users"."activated_at") = $1) activated_at.extract(Avram::ChronoUnits::Milliseconds).eq(5).to_sql.should eq [output_query, "5.0"] activated_at.extract(:milliseconds).eq(5).to_sql.should eq [output_query, "5.0"] activated_at.extract_milliseconds.eq(5).to_sql.should eq [output_query, "5.0"] end it "second" do - output_query = "SELECT users.id, users.created_at, users.updated_at, users.activated_at FROM users WHERE extract(second from users.activated_at) = $1" + output_query = %(SELECT #{QueryMe::COLUMN_SQL} FROM users WHERE extract(second from "users"."activated_at") = $1) activated_at.extract(Avram::ChronoUnits::Second).eq(5).to_sql.should eq [output_query, "5.0"] activated_at.extract(:second).eq(5).to_sql.should eq [output_query, "5.0"] activated_at.extract_second.eq(5).to_sql.should eq [output_query, "5.0"] diff --git a/spec/support/models/admin.cr b/spec/support/models/admin.cr index 987ca4fe3..dc617528c 100644 --- a/spec/support/models/admin.cr +++ b/spec/support/models/admin.cr @@ -1,5 +1,5 @@ class Admin < BaseModel - COLUMN_SQL = "admins.id, admins.created_at, admins.updated_at, admins.name" + COLUMN_SQL = %("admins"."id", "admins"."created_at", "admins"."updated_at", "admins"."name") table do column name : String diff --git a/spec/support/models/article.cr b/spec/support/models/article.cr index 06a390a75..fdf867489 100644 --- a/spec/support/models/article.cr +++ b/spec/support/models/article.cr @@ -1,5 +1,5 @@ class Article < BaseModel - COLUMN_SQL = "articles.id, articles.created_at, articles.updated_at, articles.title, articles.slug" + COLUMN_SQL = %("articles"."id", "articles"."created_at", "articles"."updated_at", "articles"."title", "articles"."slug") table do column title : String diff --git a/spec/support/models/beat.cr b/spec/support/models/beat.cr index 401bdb846..4a71b35be 100644 --- a/spec/support/models/beat.cr +++ b/spec/support/models/beat.cr @@ -1,5 +1,5 @@ class Beat < BaseModel - COLUMN_SQL = "beats.id, beats.created_at, beats.updated_at, beats.hash" + COLUMN_SQL = %("beats"."id", "beats"."created_at", "beats"."updated_at", "beats"."hash") table do column hash : Bytes diff --git a/spec/support/models/blob.cr b/spec/support/models/blob.cr index 9f2c963af..662bbf1b0 100644 --- a/spec/support/models/blob.cr +++ b/spec/support/models/blob.cr @@ -17,6 +17,7 @@ class ServerMetadata end class Blob < BaseModel + COLUMN_SQL = %("blobs"."id", "blobs"."created_at", "blobs"."updated_at", "blobs"."doc", "blobs"."metadata", "blobs"."media", "blobs"."servers") table do column doc : JSON::Any? column metadata : BlobMetadata, serialize: true diff --git a/spec/support/models/bucket.cr b/spec/support/models/bucket.cr index 31dddafc9..c17406cec 100644 --- a/spec/support/models/bucket.cr +++ b/spec/support/models/bucket.cr @@ -1,5 +1,5 @@ class Bucket < BaseModel - COLUMN_SQL = column_names.join(", ") { |col| "buckets.#{col}" } + COLUMN_SQL = column_names.join(", ") { |col| %("buckets"."#{col}") } enum Size ExtraSmall diff --git a/spec/support/models/business.cr b/spec/support/models/business.cr index d1f3500e7..5148479fa 100644 --- a/spec/support/models/business.cr +++ b/spec/support/models/business.cr @@ -1,5 +1,5 @@ class Business < BaseModel - COLUMN_SQL = "businesses.id, businesses.created_at, businesses.updated_at, businesses.name, businesses.latitude, businesses.longitude" + COLUMN_SQL = %("businesses"."id", "businesses"."created_at", "businesses"."updated_at", "businesses"."name", "businesses"."latitude", "businesses"."longitude") table do column name : String diff --git a/spec/support/models/comment.cr b/spec/support/models/comment.cr index 66934fb07..945a218dc 100644 --- a/spec/support/models/comment.cr +++ b/spec/support/models/comment.cr @@ -1,4 +1,5 @@ class Comment < BaseModel + COLUMN_SQL = %("comments"."custom_id", "comments"."created_at", "comments"."updated_at", "comments"."body", "comments"."post_id") skip_default_columns table do diff --git a/spec/support/models/company.cr b/spec/support/models/company.cr index cde21453d..360706b2d 100644 --- a/spec/support/models/company.cr +++ b/spec/support/models/company.cr @@ -1,4 +1,5 @@ class Company < BaseModel + COLUMN_SQL = %("companies"."id", "companies"."created_at", "companies"."updated_at", "companies"."sales", "companies"."earnings") table do column sales : Int64 = 0_i64 column earnings : Float64 = 0.0 diff --git a/spec/support/models/employee.cr b/spec/support/models/employee.cr index 8230f35ee..3a75f0504 100644 --- a/spec/support/models/employee.cr +++ b/spec/support/models/employee.cr @@ -1,4 +1,5 @@ class Employee < BaseModel + COLUMN_SQL = %("employees"."id", "employees"."created_at", "employees"."updated_at", "employees"."name", "employees"."manager_id") table do column name : String belongs_to manager : Manager? diff --git a/spec/support/models/issue.cr b/spec/support/models/issue.cr index 739472b0f..43933b417 100644 --- a/spec/support/models/issue.cr +++ b/spec/support/models/issue.cr @@ -1,5 +1,5 @@ class Issue < BaseModel - COLUMN_SQL = "issues.id, issues.status, issues.role" + COLUMN_SQL = %("issues"."id", "issues"."status", "issues"."role") enum Status Opened diff --git a/spec/support/models/note.cr b/spec/support/models/note.cr index ff9d739ff..6a9b297fc 100644 --- a/spec/support/models/note.cr +++ b/spec/support/models/note.cr @@ -3,6 +3,7 @@ class Note < BaseModel column from : String column read : Bool = false column text : String + column order : Int32 end end diff --git a/spec/support/models/post.cr b/spec/support/models/post.cr index 2afa7cd04..c873f30c6 100644 --- a/spec/support/models/post.cr +++ b/spec/support/models/post.cr @@ -1,4 +1,5 @@ class Post < BaseModel + COLUMN_SQL = %("posts"."custom_id", "posts"."created_at", "posts"."updated_at", "posts"."title", "posts"."published_at") skip_default_columns table do diff --git a/spec/support/models/user.cr b/spec/support/models/user.cr index a2ce6f1c9..f04d10cae 100644 --- a/spec/support/models/user.cr +++ b/spec/support/models/user.cr @@ -1,5 +1,5 @@ class User < BaseModel - COLUMN_SQL = "users.id, users.created_at, users.updated_at, users.name, users.age, users.year_born, users.nickname, users.joined_at, users.total_score, users.average_score, users.available_for_hire" + COLUMN_SQL = %("users"."id", "users"."created_at", "users"."updated_at", "users"."name", "users"."age", "users"."year_born", "users"."nickname", "users"."joined_at", "users"."total_score", "users"."average_score", "users"."available_for_hire") table do column name : String diff --git a/src/avram/join.cr b/src/avram/join.cr index a3b566bc0..4e75cbf99 100644 --- a/src/avram/join.cr +++ b/src/avram/join.cr @@ -37,11 +37,11 @@ module Avram::Join end def from_column : String - "#{@from}.#{@primary_key || "id"}" + %("#{@from}"."#{@primary_key || "id"}") end def to_column : String - "#{to}.#{@foreign_key || default_foreign_key}" + %("#{to}"."#{@foreign_key || default_foreign_key}") end def default_foreign_key : String diff --git a/src/avram/migrator/create_index_statement.cr b/src/avram/migrator/create_index_statement.cr index 2332199b0..21f085795 100644 --- a/src/avram/migrator/create_index_statement.cr +++ b/src/avram/migrator/create_index_statement.cr @@ -43,7 +43,8 @@ class Avram::Migrator::CreateIndexStatement def build index_name = @name - index_name ||= "#{@table}_#{columns.join("_")}_index" + index_name ||= "#{@table}_#{columns.join('_')}_index" + mapped_columns = columns.join(", ") { |col| %("#{col}") } String.build do |index| index << "CREATE" @@ -51,7 +52,7 @@ class Avram::Migrator::CreateIndexStatement index << " INDEX #{index_name}" index << " ON #{@table}" index << " USING #{@using.to_s.downcase}" - index << " (#{columns.join(", ")});" + index << " (#{mapped_columns});" end end diff --git a/src/avram/migrator/create_table_statement.cr b/src/avram/migrator/create_table_statement.cr index f807a3838..d9e6ba8b9 100644 --- a/src/avram/migrator/create_table_statement.cr +++ b/src/avram/migrator/create_table_statement.cr @@ -80,7 +80,7 @@ class Avram::Migrator::CreateTableStatement {% if columns.size < 2 %} {% raise "composite_primary_key expected at least two primary keys, instead got #{columns.size}" %} {% end %} - constraints << " PRIMARY KEY ({{columns.join(", ").id}})" + constraints << %( PRIMARY KEY ({{columns.map {|col| %("#{col.id}")}.join(", ").id}})) end macro add_timestamps From 850932916e847a98863e1162cef6eff7142e308c Mon Sep 17 00:00:00 2001 From: Jeremy Woertink Date: Sun, 25 Aug 2024 15:03:08 -0700 Subject: [PATCH 4/5] All specs passing again --- spec/avram/criteria_spec.cr | 24 ++++++++++---------- spec/avram/insert_spec.cr | 4 ++-- spec/avram/instrumentation_spec.cr | 4 ++-- spec/avram/join_spec.cr | 16 ++++++------- spec/avram/json_criteria_spec.cr | 22 +++++++++--------- spec/avram/query_logging_spec.cr | 2 +- src/avram/join.cr | 9 +++++--- src/avram/migrator/create_table_statement.cr | 2 +- 8 files changed, 43 insertions(+), 40 deletions(-) diff --git a/spec/avram/criteria_spec.cr b/spec/avram/criteria_spec.cr index 38827a9bb..4dd5fbdec 100644 --- a/spec/avram/criteria_spec.cr +++ b/spec/avram/criteria_spec.cr @@ -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 @@ -12,7 +12,7 @@ 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 @@ -20,59 +20,59 @@ describe Avram::Criteria 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 diff --git a/spec/avram/insert_spec.cr b/spec/avram/insert_spec.cr index c66501fcc..85507b3b6 100644 --- a/spec/avram/insert_spec.cr +++ b/spec/avram/insert_spec.cr @@ -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 diff --git a/spec/avram/instrumentation_spec.cr b/spec/avram/instrumentation_spec.cr index bafcb1c78..88c22ebea 100644 --- a/spec/avram/instrumentation_spec.cr +++ b/spec/avram/instrumentation_spec.cr @@ -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 @@ -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 diff --git a/spec/avram/join_spec.cr b/spec/avram/join_spec.cr index 06d60f6a8..0bb438b16 100644 --- a/spec/avram/join_spec.cr +++ b/spec/avram/join_spec.cr @@ -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 diff --git a/spec/avram/json_criteria_spec.cr b/spec/avram/json_criteria_spec.cr index b8fca7cbf..61aa19b49 100644 --- a/spec/avram/json_criteria_spec.cr +++ b/spec/avram/json_criteria_spec.cr @@ -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 @@ -11,31 +11,31 @@ 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 @@ -43,13 +43,13 @@ describe JSON::Any::Lucky::Criteria 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 @@ -57,13 +57,13 @@ describe JSON::Any::Lucky::Criteria 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 diff --git a/spec/avram/query_logging_spec.cr b/spec/avram/query_logging_spec.cr index 93ca144af..968335d0a 100644 --- a/spec/avram/query_logging_spec.cr +++ b/spec/avram/query_logging_spec.cr @@ -4,7 +4,7 @@ describe "Query logging" do it "logs the statement and args" do Avram::QueryLog.dexter.temp_config do |log_io| UserQuery.new.name("Bob").first? - log_io.to_s.should contain %(WHERE users.name = $1) + log_io.to_s.should contain %(WHERE \\"users\\".\\"name\\" = $1) log_io.to_s.should contain %(Bob) log_io.to_s.should contain %(duration) end diff --git a/src/avram/join.cr b/src/avram/join.cr index 4e75cbf99..d27410239 100644 --- a/src/avram/join.cr +++ b/src/avram/join.cr @@ -4,15 +4,18 @@ module Avram::Join abstract class SqlClause getter from : TableName + @using : String + def initialize( @from : TableName, @to : TableName, @primary_key : Symbol? = nil, @foreign_key : Symbol? = nil, @comparison : String? = "=", - @using : Array(Symbol) = [] of Symbol, + using : Array(Symbol) = [] of Symbol, @alias_to : TableName? = nil ) + @using = using.join(", ") { |col| %("#{col}") } end abstract def join_type : String @@ -24,8 +27,8 @@ module Avram::Join if @alias_to io << " AS #{@alias_to}" end - if !@using.empty? - io << " USING (#{@using.join(", ")})" + if @using.presence + io << " USING (#{@using})" else io << " ON #{from_column} #{@comparison} #{to_column}" end diff --git a/src/avram/migrator/create_table_statement.cr b/src/avram/migrator/create_table_statement.cr index d9e6ba8b9..fe4fbaf98 100644 --- a/src/avram/migrator/create_table_statement.cr +++ b/src/avram/migrator/create_table_statement.cr @@ -80,7 +80,7 @@ class Avram::Migrator::CreateTableStatement {% if columns.size < 2 %} {% raise "composite_primary_key expected at least two primary keys, instead got #{columns.size}" %} {% end %} - constraints << %( PRIMARY KEY ({{columns.map {|col| %("#{col.id}")}.join(", ").id}})) + constraints << %( PRIMARY KEY ({{columns.map { |col| %("#{col.id}") }.join(", ").id}})) end macro add_timestamps From ce6ff9e0bc422b399e7ec788abae54a1abdb6498 Mon Sep 17 00:00:00 2001 From: Jeremy Woertink Date: Sun, 25 Aug 2024 15:11:23 -0700 Subject: [PATCH 5/5] Applying suggestion --- spec/avram/bool_criteria_spec.cr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/avram/bool_criteria_spec.cr b/spec/avram/bool_criteria_spec.cr index 0ae59bb6e..dcd191fe4 100644 --- a/spec/avram/bool_criteria_spec.cr +++ b/spec/avram/bool_criteria_spec.cr @@ -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