/
join.cr
86 lines (73 loc) · 2.49 KB
/
join.cr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
module Marten
module DB
module Query
module SQL
# Represents an SQL join used in the context of a specific query.
#
# SQL joins are managed as a tree, which means that each join can be associated with a list of underlying
# children joins (for the joins following the considered relationship). SQL joins are "flattened" when the raw
# SQL queries are generated.
class Join
@parent : Nil | self
getter id
getter type
getter from_model
getter from_common_field
getter to_model
getter to_common_field
getter parent
getter children
def initialize(
@id : Int32,
@type : JoinType,
@from_model : Model.class,
@from_common_field : Field::Base,
@to_model : Model.class,
@to_common_field : Field::Base,
@selected : Bool
)
@children = [] of self
end
def add_child(child : self) : Nil
child.parent = self
@children << child
end
def column_name(name) : String
"#{table_alias}.#{name}"
end
def columns : Array(String)
to_model.fields.compact_map do |f|
next unless f.db_column?
column_name(f.db_column)
end + children.flat_map(&.columns)
end
def selected?
@selected
end
def table_alias : String
"t#{@id}"
end
def to_a : Array(self)
[self] + @children.flat_map(&.to_a)
end
def to_sql : String
statement = case @type
when JoinType::INNER
"INNER JOIN"
when JoinType::LEFT_OUTER
"LEFT OUTER JOIN"
end
to_table_name = to_model.db_table
to_table_common_column = to_common_field.db_column
from_table_name = parent.try(&.table_alias) || from_model.db_table
from_table_common_column = from_common_field.db_column
sql = "#{statement} #{to_table_name} #{table_alias} " \
"ON (#{from_table_name}.#{from_table_common_column} = #{column_name(to_table_common_column)})"
([sql] + children.flat_map(&.to_sql)).join(" ")
end
protected setter parent
end
end
end
end
end