Skip to content

Commit 3f7607b

Browse files
committed
custom upsert support
1 parent 4d328d5 commit 3f7607b

File tree

2 files changed

+38
-26
lines changed

2 files changed

+38
-26
lines changed

Sources/PostgreSQL/SQL/PostgreSQLInsert.swift

+23-24
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
public struct PostgreSQLInsert: SQLInsert {
22
/// See `SQLInsert`.
33
public static func insert(_ table: PostgreSQLTableIdentifier) -> PostgreSQLInsert {
4-
return .init(insert: .insert(table), returning: [])
4+
return self.init(table: table, columns: [], values: [], upsert: nil, returning: [])
55
}
66

77
/// See `SQLInsert`.
@@ -16,37 +16,36 @@ public struct PostgreSQLInsert: SQLInsert {
1616
/// See `SQLInsert`.
1717
public typealias Upsert = PostgreSQLUpsert
1818

19-
/// Root insert statement.
20-
private var insert: GenericSQLInsert<TableIdentifier, ColumnIdentifier, Expression, Upsert>
21-
22-
/// `RETURNING *`
23-
public var returning: [PostgreSQLSelectExpression]
24-
19+
/// Table to insert into.
20+
public var table: TableIdentifier
2521
/// See `SQLInsert`.
26-
public var columns: [PostgreSQLColumnIdentifier] {
27-
get { return insert.columns }
28-
set { insert.columns = newValue }
29-
}
22+
public var columns: [PostgreSQLColumnIdentifier]
3023

3124
/// See `SQLInsert`.
32-
public var values: [[PostgreSQLExpression]] {
33-
get { return insert.values }
34-
set { insert.values = newValue}
35-
}
25+
public var values: [[PostgreSQLExpression]]
3626

37-
/// See `SQLInsert`.
38-
public var upsert: PostgreSQLUpsert? {
39-
get { return insert.upsert }
40-
set { insert.upsert = newValue }
41-
}
27+
/// Optional "upsert" condition.
28+
public var upsert: PostgreSQLUpsert?
29+
30+
/// `RETURNING *`
31+
public var returning: [PostgreSQLSelectExpression]
4232

4333
/// See `SQLSerializable`.
4434
public func serialize(_ binds: inout [Encodable]) -> String {
45-
if returning.isEmpty {
46-
return insert.serialize(&binds)
47-
} else {
48-
return insert.serialize(&binds) + " RETURNING " + returning.serialize(&binds)
35+
var sql: [String] = []
36+
sql.append("INSERT INTO")
37+
sql.append(table.serialize(&binds))
38+
sql.append("(" + columns.serialize(&binds) + ")")
39+
sql.append("VALUES")
40+
sql.append(values.map { "(" + $0.serialize(&binds) + ")"}.joined(separator: ", "))
41+
if let upsert = upsert {
42+
sql.append(upsert.serialize(&binds))
43+
}
44+
if !returning.isEmpty {
45+
sql.append("RETURNING")
46+
sql.append(returning.serialize(&binds))
4947
}
48+
return sql.joined(separator: " ")
5049
}
5150
}
5251

Sources/PostgreSQL/SQL/PostgreSQLUpsert.swift

+15-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
public struct PostgreSQLUpsert: SQLUpsert {
1+
public struct PostgreSQLUpsert {
22
/// See `SQLUpsert`.
33
public typealias Identifier = PostgreSQLIdentifier
44

55
/// See `SQLUpsert`.
66
public typealias Expression = PostgreSQLExpression
77

88
/// See `SQLUpsert`.
9-
public static func upsert(_ values: [(Identifier, Expression)]) -> PostgreSQLUpsert {
9+
public static func upsert(_ column: [PostgreSQLColumnIdentifier], _ values: [(Identifier, Expression)]) -> PostgreSQLUpsert {
1010
return self.init(columns: [.column(nil, .identifier("id"))], values: values)
1111
}
1212

@@ -26,3 +26,16 @@ public struct PostgreSQLUpsert: SQLUpsert {
2626
return sql.joined(separator: " ")
2727
}
2828
}
29+
30+
extension SQLInsertBuilder where Connection.Query.Insert == PostgreSQLInsert {
31+
public func onConflict<T, V, E>(_ key: KeyPath<T, V>, set value: E) -> Self where
32+
T: PostgreSQLTable, E: Encodable
33+
{
34+
let row = SQLQueryEncoder(PostgreSQLExpression.self).encode(value)
35+
let values = row.map { row -> (PostgreSQLIdentifier, PostgreSQLExpression) in
36+
return (.identifier(row.key), row.value)
37+
}
38+
insert.upsert = .upsert([.keyPath(key)], values)
39+
return self
40+
}
41+
}

0 commit comments

Comments
 (0)