From 97758ab6c844873d656718743662e83661533726 Mon Sep 17 00:00:00 2001 From: Jeremy Woertink Date: Sun, 17 Mar 2024 09:45:55 -0700 Subject: [PATCH 1/2] Testing issue #1011 --- .../20240317161918_create_interviews.cr | 14 +++++++++++++ spec/avram/query_associations_spec.cr | 12 +++++++++++ spec/support/factories/interview_factory.cr | 20 +++++++++++++++++++ spec/support/models/interview.cr | 9 +++++++++ 4 files changed, 55 insertions(+) create mode 100644 db/migrations/20240317161918_create_interviews.cr create mode 100644 spec/support/factories/interview_factory.cr create mode 100644 spec/support/models/interview.cr diff --git a/db/migrations/20240317161918_create_interviews.cr b/db/migrations/20240317161918_create_interviews.cr new file mode 100644 index 000000000..f2c1d8833 --- /dev/null +++ b/db/migrations/20240317161918_create_interviews.cr @@ -0,0 +1,14 @@ +class CreateInterviews::V20240317161918 < Avram::Migrator::Migration::V1 + def migrate + create table_for(Interview) do + primary_key id : Int64 + add_timestamps + add_belongs_to interviewer : User, on_delete: :cascade + add_belongs_to interviewee : User, on_delete: :cascade + end + end + + def rollback + drop table_for(Interview) + end +end diff --git a/spec/avram/query_associations_spec.cr b/spec/avram/query_associations_spec.cr index 311d7460b..49424a49e 100644 --- a/spec/avram/query_associations_spec.cr +++ b/spec/avram/query_associations_spec.cr @@ -176,4 +176,16 @@ describe "Query associations" do result.should eq(product) end + + it "handles aliases", focus: true do + interviewer = UserFactory.create(&.available_for_hire(false).name("Interviewer")) + interviewee = UserFactory.create(&.available_for_hire(true).name("Interviewee")) + UserFactory.create(&.available_for_hire(false).name("Employed")) + InterviewFactory.create(&.interviewee(interviewee).interviewer(interviewer)) + + InterviewQuery.new + .where_interviewer(UserQuery.new.available_for_hire(false)) + .where_interviewee(UserQuery.new.available_for_hire(true)) + .to_prepared_sql.should eq("nothing") + end end diff --git a/spec/support/factories/interview_factory.cr b/spec/support/factories/interview_factory.cr new file mode 100644 index 000000000..9613b38f2 --- /dev/null +++ b/spec/support/factories/interview_factory.cr @@ -0,0 +1,20 @@ +class InterviewFactory < BaseFactory + def initialize + before_save do + if operation.interviewer_id.value.nil? + interviewer(UserFactory.create) + end + if operation.interviewee_id.value.nil? + interviewee(UserFactory.create) + end + end + end + + def interviewer(u : User) + interviewer_id(u.id) + end + + def interviewee(u : User) + interviewee_id(u.id) + end +end diff --git a/spec/support/models/interview.cr b/spec/support/models/interview.cr new file mode 100644 index 000000000..b42025886 --- /dev/null +++ b/spec/support/models/interview.cr @@ -0,0 +1,9 @@ +class Interview < BaseModel + table do + belongs_to interviewer : User + belongs_to interviewee : User + end +end + +class InterviewQuery < Interview::BaseQuery +end From cb082450313575a890085fcf5de85365458f37ad Mon Sep 17 00:00:00 2001 From: Jeremy Woertink Date: Mon, 18 Mar 2024 13:21:26 -0700 Subject: [PATCH 2/2] Let the table_name of a query object be overriden. --- spec/avram/query_associations_spec.cr | 13 ++++++++----- src/avram/base_query_template.cr | 5 +++++ src/avram/queryable.cr | 2 +- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/spec/avram/query_associations_spec.cr b/spec/avram/query_associations_spec.cr index 49424a49e..69de0cbc5 100644 --- a/spec/avram/query_associations_spec.cr +++ b/spec/avram/query_associations_spec.cr @@ -177,15 +177,18 @@ describe "Query associations" do result.should eq(product) end - it "handles aliases", focus: true do + it "handles aliases" do interviewer = UserFactory.create(&.available_for_hire(false).name("Interviewer")) interviewee = UserFactory.create(&.available_for_hire(true).name("Interviewee")) - UserFactory.create(&.available_for_hire(false).name("Employed")) + employed = UserFactory.create(&.available_for_hire(false).name("Employed")) InterviewFactory.create(&.interviewee(interviewee).interviewer(interviewer)) + InterviewFactory.create(&.interviewee(employed).interviewer(interviewer)) InterviewQuery.new - .where_interviewer(UserQuery.new.available_for_hire(false)) - .where_interviewee(UserQuery.new.available_for_hire(true)) - .to_prepared_sql.should eq("nothing") + .join(Avram::Join::Inner.new(:interviews, :users, alias_to: :interviewers, primary_key: :interviewer_id, foreign_key: :id)) + .join(Avram::Join::Inner.new(:interviews, :users, alias_to: :interviewees, primary_key: :interviewee_id, foreign_key: :id)) + .where_interviewer(UserQuery.new("interviewers").available_for_hire(false), auto_inner_join: false) + .where_interviewee(UserQuery.new("interviewees").available_for_hire(true), auto_inner_join: false) + .select_count.should eq(1) end end diff --git a/src/avram/base_query_template.cr b/src/avram/base_query_template.cr index 9c904fff9..f2bfdcc4f 100644 --- a/src/avram/base_query_template.cr +++ b/src/avram/base_query_template.cr @@ -4,6 +4,11 @@ class Avram::BaseQueryTemplate def_clone include Avram::Queryable({{ type }}) + getter table_name : String = {{ type }}.table_name + + def initialize(@table_name : String = {{ type }}.table_name) + end + {% if type.resolve.has_constant?("PRIMARY_KEY_NAME") %} include Avram::PrimaryKeyQueryable({{ type }}) {% end %} diff --git a/src/avram/queryable.cr b/src/avram/queryable.cr index ccbb9bdb0..c3beb882f 100644 --- a/src/avram/queryable.cr +++ b/src/avram/queryable.cr @@ -7,7 +7,7 @@ module Avram::Queryable(T) .select(schema_class.column_names) end - delegate :database, :table_name, :primary_key_name, to: T + delegate :database, :primary_key_name, to: T macro included def self.new_with_existing_query(query : Avram::QueryBuilder)