Skip to content

Commit dc88f8d

Browse files
fix: hide DB credentials and handle duplicate inserts when using AlloyDB (#3021)
Co-authored-by: Olivier Bourgeois <[email protected]>
1 parent 896f214 commit dc88f8d

File tree

1 file changed

+35
-28
lines changed

1 file changed

+35
-28
lines changed

src/cartservice/src/cartstore/AlloyDBCartStore.cs

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -59,39 +59,46 @@ public AlloyDBCartStore(IConfiguration configuration)
5959
}
6060

6161

62-
public async Task AddItemAsync(string userId, string productId, int quantity)
62+
public async Task AddItemAsync(string userId, string productId, int quantity)
63+
{
64+
Console.WriteLine($"AddItemAsync for {userId} called");
65+
try
6366
{
64-
Console.WriteLine($"AddItemAsync for {userId} called");
65-
try
67+
await using var dataSource = NpgsqlDataSource.Create(connectionString);
68+
69+
var fetchCmd = $"SELECT quantity FROM {tableName} WHERE userID='{userId}' AND productID='{productId}'";
70+
var currentQuantity = 0;
71+
var cmdRead = dataSource.CreateCommand(fetchCmd);
72+
await using (var reader = await cmdRead.ExecuteReaderAsync())
6673
{
67-
await using var dataSource = NpgsqlDataSource.Create(connectionString);
74+
while (await reader.ReadAsync())
75+
currentQuantity += reader.GetInt32(0);
76+
}
6877

69-
// Fetch the current quantity for our userId/productId tuple
70-
var fetchCmd = $"SELECT quantity FROM {tableName} WHERE userID='{userId}' AND productID='{productId}'";
71-
var currentQuantity = 0;
72-
var cmdRead = dataSource.CreateCommand(fetchCmd);
73-
await using (var reader = await cmdRead.ExecuteReaderAsync())
74-
{
75-
while (await reader.ReadAsync())
76-
currentQuantity += reader.GetInt32(0);
77-
}
78-
var totalQuantity = quantity + currentQuantity;
78+
var totalQuantity = quantity + currentQuantity;
7979

80-
var insertCmd = $"INSERT INTO {tableName} (userId, productId, quantity) VALUES ('{userId}', '{productId}', {totalQuantity})";
81-
await using (var cmdInsert = dataSource.CreateCommand(insertCmd))
82-
{
83-
await Task.Run(() =>
84-
{
85-
return cmdInsert.ExecuteNonQueryAsync();
86-
});
87-
}
88-
}
89-
catch (Exception ex)
80+
// Use INSERT ... ON CONFLICT to prevent duplicate key error
81+
var insertCmd = $@"
82+
INSERT INTO {tableName} (userId, productId, quantity)
83+
VALUES ('{userId}', '{productId}', {totalQuantity})
84+
ON CONFLICT (userId, productId)
85+
DO UPDATE SET quantity = {totalQuantity};
86+
";
87+
88+
await using (var cmdInsert = dataSource.CreateCommand(insertCmd))
9089
{
91-
throw new RpcException(
92-
new Status(StatusCode.FailedPrecondition, $"Can't access cart storage at {connectionString}. {ex}"));
90+
await Task.Run(() =>
91+
{
92+
return cmdInsert.ExecuteNonQueryAsync();
93+
});
9394
}
9495
}
96+
catch (Exception ex)
97+
{
98+
throw new RpcException(
99+
new Status(StatusCode.FailedPrecondition, $"Unable to access cart storage due to an internal error. {ex}"));
100+
}
101+
}
95102

96103

97104
public async Task<Hipstershop.Cart> GetCartAsync(string userId)
@@ -125,7 +132,7 @@ await Task.Run(() =>
125132
catch (Exception ex)
126133
{
127134
throw new RpcException(
128-
new Status(StatusCode.FailedPrecondition, $"Can't access cart storage at {connectionString}. {ex}"));
135+
new Status(StatusCode.FailedPrecondition, $"Unable to access cart storage due to an internal error. {ex}"));
129136
}
130137
return cart;
131138
}
@@ -150,7 +157,7 @@ await Task.Run(() =>
150157
catch (Exception ex)
151158
{
152159
throw new RpcException(
153-
new Status(StatusCode.FailedPrecondition, $"Can't access cart storage at {connectionString}. {ex}"));
160+
new Status(StatusCode.FailedPrecondition, $"Unable to access cart storage due to an internal error. {ex}"));
154161
}
155162
}
156163

0 commit comments

Comments
 (0)