Skip to content

Commit 40ad451

Browse files
committed
Added Avram::Join::Raw. (#1048)
1 parent 3a27ebb commit 40ad451

File tree

3 files changed

+74
-0
lines changed

3 files changed

+74
-0
lines changed

Diff for: src/avram/join.cr

+56
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,60 @@ module Avram::Join
7676
"FULL"
7777
end
7878
end
79+
80+
class Raw
81+
@clause : String
82+
83+
def self.new(statement : String, *bind_vars)
84+
new(statement, args: bind_vars.to_a)
85+
end
86+
87+
def initialize(statement : String, *, args bind_vars : Array)
88+
ensure_enough_bind_variables_for!(statement, bind_vars)
89+
@clause = build_clause(statement, bind_vars)
90+
end
91+
92+
def prepare(placeholder_supplier : Proc(String)) : String
93+
@clause
94+
end
95+
96+
def to_sql : String
97+
@clause
98+
end
99+
100+
def clone : self
101+
self
102+
end
103+
104+
private def ensure_enough_bind_variables_for!(statement, bind_vars)
105+
bindings = statement.chars.select(&.== '?')
106+
if bindings.size != bind_vars.size
107+
raise "wrong number of bind variables (#{bind_vars.size} for #{bindings.size}) in #{statement}"
108+
end
109+
end
110+
111+
private def build_clause(statement, bind_vars)
112+
bind_vars.each do |arg|
113+
encoded_arg = prepare_for_execution(arg)
114+
statement = statement.sub('?', encoded_arg)
115+
end
116+
statement
117+
end
118+
119+
private def prepare_for_execution(value)
120+
if value.is_a?(Array)
121+
"'#{PQ::Param.encode_array(value)}'"
122+
else
123+
escape_if_needed(value)
124+
end
125+
end
126+
127+
private def escape_if_needed(value)
128+
if value.is_a?(String) || value.is_a?(Slice(UInt8))
129+
PG::EscapeHelper.escape_literal(value)
130+
else
131+
value
132+
end
133+
end
134+
end
79135
end

Diff for: src/avram/query_builder.cr

+10
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ class Avram::QueryBuilder
88
@offset : Int32?
99
@wheres = [] of Avram::Where::Condition
1010
@joins = [] of Avram::Join::SqlClause
11+
@raw_joins = [] of Avram::Join::Raw
1112
@orders = [] of Avram::OrderByClause
1213
@groups = [] of ColumnName
1314
@selections : String = "*"
@@ -318,6 +319,15 @@ class Avram::QueryBuilder
318319
@joins.uniq(&.to_sql)
319320
end
320321

322+
def join(raw_join_clause : Avram::Join::Raw) : self
323+
@raw_joins << raw_join_clause
324+
self
325+
end
326+
327+
def joins : Array(Avram::Join::Raw)
328+
@raw_joins.uniq(&.to_sql)
329+
end
330+
321331
private def joins_sql : String
322332
joins.join(" ", &.to_sql)
323333
end

Diff for: src/avram/queryable.cr

+8
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,14 @@ module Avram::Queryable(T)
124124
clone.tap &.query.join(join_clause)
125125
end
126126

127+
def join(statement : String, *bind_vars) : self
128+
join(statement, args: bind_vars.to_a)
129+
end
130+
131+
def join(statement : String, *, args bind_vars : Array) : self
132+
clone.tap &.query.join(Avram::Join::Raw.new(statement, args: bind_vars))
133+
end
134+
127135
def where(column : Symbol, value) : self
128136
clone.tap &.query.where(Avram::Where::Equal.new(column, value.to_s))
129137
end

0 commit comments

Comments
 (0)