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..69de0cbc5 100644 --- a/spec/avram/query_associations_spec.cr +++ b/spec/avram/query_associations_spec.cr @@ -176,4 +176,19 @@ describe "Query associations" do result.should eq(product) end + + it "handles aliases" do + interviewer = UserFactory.create(&.available_for_hire(false).name("Interviewer")) + interviewee = UserFactory.create(&.available_for_hire(true).name("Interviewee")) + employed = UserFactory.create(&.available_for_hire(false).name("Employed")) + InterviewFactory.create(&.interviewee(interviewee).interviewer(interviewer)) + InterviewFactory.create(&.interviewee(employed).interviewer(interviewer)) + + InterviewQuery.new + .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/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 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)