|
1 | | -class Avram::BulkUpsert |
| 1 | +class Avram::BulkUpsert(T) |
2 | 2 | alias Params = Hash(Symbol, String) | Hash(Symbol, String?) | Hash(Symbol, Nil) |
3 | 3 |
|
4 | | - def initialize(@table : TableName, |
5 | | - @records : Array(Params), |
6 | | - @column_names : Array(Symbol) = [] of Symbol) |
| 4 | + def initialize(@records : Array(Params)) |
7 | 5 | end |
8 | 6 |
|
9 | 7 | def statement |
10 | | - "insert into #{@table}(#{fields}) values(#{values}) returning *" |
| 8 | + [ |
| 9 | + "insert into #{table}(#{fields})", |
| 10 | + "values #{value_placeholders}", |
| 11 | + "ON CONFLICT DO UPDATE SET #{updates}", |
| 12 | + "returning #{returning}", |
| 13 | + ].join(" ") |
| 14 | + end |
| 15 | + |
| 16 | + private def table |
| 17 | + T.table_name |
| 18 | + end |
| 19 | + |
| 20 | + private def updates |
| 21 | + conflict_updates = T.column_names.uniq.map do |column| |
| 22 | + "SET #{column}=EXCLUDED.#{column}" |
| 23 | + end |
| 24 | + |
| 25 | + if T.column_names.includes?(:updated_at) |
| 26 | + conflict_updates.push("SET updated_at=NOW()").join(", ") |
| 27 | + else |
| 28 | + conflict_updates.join(", ") |
| 29 | + end |
| 30 | + end |
| 31 | + |
| 32 | + private def returning |
| 33 | + "id" |
11 | 34 | end |
12 | 35 |
|
13 | 36 | private def fields |
14 | | - @column_names.join(", ") |
| 37 | + T.column_names.join(", ") |
| 38 | + end |
| 39 | + |
| 40 | + def args |
| 41 | + @records.map &.values |
15 | 42 | end |
16 | 43 |
|
17 | | - private def record_values(record) |
| 44 | + private def placeholder_values(record) |
18 | 45 | values = record.values.map_with_index(1) do |_value, index| |
19 | 46 | "$#{index}" |
20 | 47 | end.join(", ") |
21 | 48 |
|
22 | 49 | "(#{values})" |
23 | 50 | end |
24 | 51 |
|
25 | | - private def values |
| 52 | + private def value_placeholders |
26 | 53 | @records.map do |record| |
27 | | - record_values(record) |
| 54 | + placeholder_values(record) |
28 | 55 | end.join(", ") |
29 | 56 | end |
30 | 57 | end |
0 commit comments