Skip to content

Commit 11bd067

Browse files
committed
fix: fixes and error handling changes
1 parent 57f7d04 commit 11bd067

13 files changed

+1020
-137
lines changed

src/main/java/io/supertokens/storage/postgresql/Start.java

Lines changed: 290 additions & 19 deletions
Large diffs are not rendered by default.

src/main/java/io/supertokens/storage/postgresql/queries/ActiveUsersQueries.java

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55
import io.supertokens.storage.postgresql.Start;
66
import io.supertokens.storage.postgresql.config.Config;
77
import io.supertokens.storage.postgresql.utils.Utils;
8+
import org.jetbrains.annotations.TestOnly;
89

910
import java.sql.Connection;
1011
import java.sql.SQLException;
11-
12-
import org.jetbrains.annotations.TestOnly;
12+
import java.util.HashMap;
13+
import java.util.List;
14+
import java.util.Map;
1315

1416
import static io.supertokens.storage.postgresql.QueryExecutorTemplate.execute;
1517
import static io.supertokens.storage.postgresql.QueryExecutorTemplate.update;
@@ -133,6 +135,30 @@ public static Long getLastActiveByUserId(Start start, AppIdentifier appIdentifie
133135
}
134136
}
135137

138+
public static Map<String, Long> getLastActiveByMultipleUserIds(Start start, AppIdentifier appIdentifier, List<String> userIds)
139+
throws StorageQueryException {
140+
String QUERY = "SELECT user_id, last_active_time FROM " + Config.getConfig(start).getUserLastActiveTable()
141+
+ " WHERE app_id = ? AND user_id IN ( " + Utils.generateCommaSeperatedQuestionMarks(userIds.size())+ " )";
142+
143+
try {
144+
return execute(start, QUERY, pst -> {
145+
pst.setString(1, appIdentifier.getAppId());
146+
for (int i = 0; i < userIds.size(); i++) {
147+
pst.setString(2+i, userIds.get(i));
148+
}
149+
}, res -> {
150+
Map<String, Long> lastActiveByUserIds = new HashMap<>();
151+
if (res.next()) {
152+
String userId = res.getString("user_id");
153+
lastActiveByUserIds.put(userId, res.getLong("last_active_time"));
154+
}
155+
return lastActiveByUserIds;
156+
});
157+
} catch (SQLException e) {
158+
throw new StorageQueryException(e);
159+
}
160+
}
161+
136162
public static void deleteUserActive_Transaction(Connection con, Start start, AppIdentifier appIdentifier,
137163
String userId)
138164
throws StorageQueryException, SQLException {

src/main/java/io/supertokens/storage/postgresql/queries/BulkImportQueries.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,12 @@
2929
import javax.annotation.Nonnull;
3030
import javax.annotation.Nullable;
3131
import java.sql.Connection;
32+
import java.sql.PreparedStatement;
3233
import java.sql.ResultSet;
3334
import java.sql.SQLException;
3435
import java.util.ArrayList;
3536
import java.util.List;
37+
import java.util.Map;
3638

3739
import static io.supertokens.storage.postgresql.QueryExecutorTemplate.execute;
3840
import static io.supertokens.storage.postgresql.QueryExecutorTemplate.update;
@@ -121,6 +123,32 @@ public static void updateBulkImportUserStatus_Transaction(Start start, Connectio
121123
});
122124
}
123125

126+
public static void updateMultipleBulkImportUsersStatusToError_Transaction(Start start, Connection con, AppIdentifier appIdentifier,
127+
@Nonnull Map<String,String> bulkImportUserIdToErrorMessage)
128+
throws SQLException {
129+
BULK_IMPORT_USER_STATUS errorStatus = BULK_IMPORT_USER_STATUS.FAILED;
130+
String query = "UPDATE " + Config.getConfig(start).getBulkImportUsersTable()
131+
+ " SET status = ?, error_msg = ?, updated_at = ? WHERE app_id = ? and id = ?";
132+
133+
PreparedStatement setErrorStatement = con.prepareStatement(query);
134+
135+
int counter = 0;
136+
for(String bulkImportUserId : bulkImportUserIdToErrorMessage.keySet()){
137+
setErrorStatement.setString(1, errorStatus.toString());
138+
setErrorStatement.setString(2, bulkImportUserIdToErrorMessage.get(bulkImportUserId));
139+
setErrorStatement.setLong(3, System.currentTimeMillis());
140+
setErrorStatement.setString(4, appIdentifier.getAppId());
141+
setErrorStatement.setString(5, bulkImportUserId);
142+
setErrorStatement.addBatch();
143+
144+
if(counter % 100 == 0) {
145+
setErrorStatement.executeBatch();
146+
}
147+
}
148+
149+
setErrorStatement.executeBatch();
150+
}
151+
124152
public static List<BulkImportUser> getBulkImportUsersAndChangeStatusToProcessing(Start start,
125153
AppIdentifier appIdentifier,
126154
@Nonnull Integer limit)
@@ -129,7 +157,7 @@ public static List<BulkImportUser> getBulkImportUsersAndChangeStatusToProcessing
129157
return start.startTransaction(con -> {
130158
Connection sqlCon = (Connection) con.getConnection();
131159
try {
132-
// NOTE: On average, we take about 66 seconds to process 1000 users. If, for any reason, the bulk import users were marked as processing but couldn't be processed within 10 minutes, we'll attempt to process them again.
160+
// NOTE: On average, we take about 60 seconds to process 10k users. If, for any reason, the bulk import users were marked as processing but couldn't be processed within 10 minutes, we'll attempt to process them again.
133161

134162
// "FOR UPDATE" ensures that multiple cron jobs don't read the same rows simultaneously.
135163
// If one process locks the first 1000 rows, others will wait for the lock to be released.

src/main/java/io/supertokens/storage/postgresql/queries/EmailPasswordQueries.java

Lines changed: 122 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -336,94 +336,81 @@ public static AuthRecipeUserInfo signUp(Start start, TenantIdentifier tenantIden
336336
});
337337
}
338338

339-
public static void signUpMultiple(Start start, List<EmailPasswordImportUser> usersToSignUp)
340-
throws StorageQueryException, StorageTransactionLogicException {
341-
start.startTransaction(con -> {
342-
Connection sqlCon = (Connection) con.getConnection();
343-
try {
344-
String app_id_to_user_id_QUERY = "INSERT INTO " + getConfig(start).getAppIdToUserIdTable()
345-
+ "(app_id, user_id, primary_or_recipe_user_id, recipe_id)" + " VALUES(?, ?, ?, ?)";
339+
public static void signUpMultipleForBulkImport_Transaction(Start start, Connection sqlCon, List<EmailPasswordImportUser> usersToSignUp)
340+
throws StorageQueryException, StorageTransactionLogicException, SQLException {
341+
try {
342+
String app_id_to_user_id_QUERY = "INSERT INTO " + getConfig(start).getAppIdToUserIdTable()
343+
+ "(app_id, user_id, primary_or_recipe_user_id, recipe_id)" + " VALUES(?, ?, ?, ?)";
344+
345+
String all_auth_recipe_users_QUERY = "INSERT INTO " + getConfig(start).getUsersTable() +
346+
"(app_id, tenant_id, user_id, primary_or_recipe_user_id, recipe_id, time_joined, " +
347+
"primary_or_recipe_user_time_joined)" +
348+
" VALUES(?, ?, ?, ?, ?, ?, ?)";
349+
350+
String emailpassword_users_QUERY = "INSERT INTO " + getConfig(start).getEmailPasswordUsersTable()
351+
+ "(app_id, user_id, email, password_hash, time_joined)" + " VALUES(?, ?, ?, ?, ?)";
352+
353+
String emailpassword_users_to_tenant_QUERY =
354+
"INSERT INTO " + getConfig(start).getEmailPasswordUserToTenantTable()
355+
+ "(app_id, tenant_id, user_id, email)" + " VALUES(?, ?, ?, ?)";
346356

347-
String all_auth_recipe_users_QUERY = "INSERT INTO " + getConfig(start).getUsersTable() +
348-
"(app_id, tenant_id, user_id, primary_or_recipe_user_id, recipe_id, time_joined, " +
349-
"primary_or_recipe_user_time_joined)" +
350-
" VALUES(?, ?, ?, ?, ?, ?, ?)";
351-
352-
String emailpassword_users_QUERY = "INSERT INTO " + getConfig(start).getEmailPasswordUsersTable()
353-
+ "(app_id, user_id, email, password_hash, time_joined)" + " VALUES(?, ?, ?, ?, ?)";
354-
355-
String emailpassword_users_to_tenant_QUERY = "INSERT INTO " + getConfig(start).getEmailPasswordUserToTenantTable()
356-
+ "(app_id, tenant_id, user_id, email)" + " VALUES(?, ?, ?, ?)";
357-
358-
PreparedStatement appIdToUserId = sqlCon.prepareStatement(app_id_to_user_id_QUERY);
359-
PreparedStatement allAuthRecipeUsers = sqlCon.prepareStatement(all_auth_recipe_users_QUERY);
360-
PreparedStatement emailPasswordUsers = sqlCon.prepareStatement(emailpassword_users_QUERY);
361-
PreparedStatement emailPasswordUsersToTenant = sqlCon.prepareStatement(emailpassword_users_to_tenant_QUERY);
362-
363-
int counter = 0;
364-
for(EmailPasswordImportUser user: usersToSignUp) {
365-
String userId = user.userId;
366-
TenantIdentifier tenantIdentifier = user.tenantIdentifier;
367-
368-
appIdToUserId.setString(1, tenantIdentifier.getAppId());
369-
appIdToUserId.setString(2, userId);
370-
appIdToUserId.setString(3, userId);
371-
appIdToUserId.setString(4, EMAIL_PASSWORD.toString());
372-
appIdToUserId.addBatch();
373-
374-
375-
allAuthRecipeUsers.setString(1, tenantIdentifier.getAppId());
376-
allAuthRecipeUsers.setString(2, tenantIdentifier.getTenantId());
377-
allAuthRecipeUsers.setString(3, userId);
378-
allAuthRecipeUsers.setString(4, userId);
379-
allAuthRecipeUsers.setString(5, EMAIL_PASSWORD.toString());
380-
allAuthRecipeUsers.setLong(6, user.timeJoinedMSSinceEpoch);
381-
allAuthRecipeUsers.setLong(7, user.timeJoinedMSSinceEpoch);
382-
allAuthRecipeUsers.addBatch();
383-
384-
emailPasswordUsers.setString(1, tenantIdentifier.getAppId());
385-
emailPasswordUsers.setString(2, userId);
386-
emailPasswordUsers.setString(3, user.email);
387-
emailPasswordUsers.setString(4, user.passwordHash);
388-
emailPasswordUsers.setLong(5, user.timeJoinedMSSinceEpoch);
389-
emailPasswordUsers.addBatch();
390-
391-
emailPasswordUsersToTenant.setString(1, tenantIdentifier.getAppId());
392-
emailPasswordUsersToTenant.setString(2, tenantIdentifier.getTenantId());
393-
emailPasswordUsersToTenant.setString(3, userId);
394-
emailPasswordUsersToTenant.setString(4, user.email);
395-
emailPasswordUsersToTenant.addBatch();
396-
counter++;
397-
if(counter % 100 == 0) {
398-
appIdToUserId.executeBatch();
399-
allAuthRecipeUsers.executeBatch();
400-
emailPasswordUsers.executeBatch();
401-
emailPasswordUsersToTenant.executeBatch();
402-
}
357+
PreparedStatement appIdToUserId = sqlCon.prepareStatement(app_id_to_user_id_QUERY);
358+
PreparedStatement allAuthRecipeUsers = sqlCon.prepareStatement(all_auth_recipe_users_QUERY);
359+
PreparedStatement emailPasswordUsers = sqlCon.prepareStatement(emailpassword_users_QUERY);
360+
PreparedStatement emailPasswordUsersToTenant = sqlCon.prepareStatement(emailpassword_users_to_tenant_QUERY);
361+
362+
int counter = 0;
363+
for (EmailPasswordImportUser user : usersToSignUp) {
364+
String userId = user.userId;
365+
TenantIdentifier tenantIdentifier = user.tenantIdentifier;
366+
367+
appIdToUserId.setString(1, tenantIdentifier.getAppId());
368+
appIdToUserId.setString(2, userId);
369+
appIdToUserId.setString(3, userId);
370+
appIdToUserId.setString(4, EMAIL_PASSWORD.toString());
371+
appIdToUserId.addBatch();
372+
373+
374+
allAuthRecipeUsers.setString(1, tenantIdentifier.getAppId());
375+
allAuthRecipeUsers.setString(2, tenantIdentifier.getTenantId());
376+
allAuthRecipeUsers.setString(3, userId);
377+
allAuthRecipeUsers.setString(4, userId);
378+
allAuthRecipeUsers.setString(5, EMAIL_PASSWORD.toString());
379+
allAuthRecipeUsers.setLong(6, user.timeJoinedMSSinceEpoch);
380+
allAuthRecipeUsers.setLong(7, user.timeJoinedMSSinceEpoch);
381+
allAuthRecipeUsers.addBatch();
382+
383+
emailPasswordUsers.setString(1, tenantIdentifier.getAppId());
384+
emailPasswordUsers.setString(2, userId);
385+
emailPasswordUsers.setString(3, user.email);
386+
emailPasswordUsers.setString(4, user.passwordHash);
387+
emailPasswordUsers.setLong(5, user.timeJoinedMSSinceEpoch);
388+
emailPasswordUsers.addBatch();
389+
390+
emailPasswordUsersToTenant.setString(1, tenantIdentifier.getAppId());
391+
emailPasswordUsersToTenant.setString(2, tenantIdentifier.getTenantId());
392+
emailPasswordUsersToTenant.setString(3, userId);
393+
emailPasswordUsersToTenant.setString(4, user.email);
394+
emailPasswordUsersToTenant.addBatch();
395+
counter++;
396+
if (counter % 100 == 0) {
397+
appIdToUserId.executeBatch();
398+
allAuthRecipeUsers.executeBatch();
399+
emailPasswordUsers.executeBatch();
400+
emailPasswordUsersToTenant.executeBatch();
403401
}
402+
}
404403

405-
//execute the remaining ones
406-
appIdToUserId.executeBatch();
407-
allAuthRecipeUsers.executeBatch();
408-
emailPasswordUsers.executeBatch();
409-
emailPasswordUsersToTenant.executeBatch();
404+
//execute the remaining ones
405+
appIdToUserId.executeBatch();
406+
allAuthRecipeUsers.executeBatch();
407+
emailPasswordUsers.executeBatch();
408+
emailPasswordUsersToTenant.executeBatch();
410409

411-
//UserInfoPartial userInfo = new UserInfoPartial(userId, email, passwordHash, timeJoined);
412-
// fillUserInfoWithTenantIds_transaction(start, sqlCon, tenantIdentifier.toAppIdentifier(), userInfo);
413-
// fillUserInfoWithVerified_transaction(start, sqlCon, tenantIdentifier.toAppIdentifier(), userInfo);
414-
sqlCon.commit();
415-
//return AuthRecipeUserInfo.create(userId, false, userInfo.toLoginMethod());
416-
} catch (SQLException throwables) {
417-
throwables.printStackTrace(System.out);
418-
SQLException next = throwables.getNextException();
419-
while(next != null) {
420-
next.printStackTrace(System.out);
421-
next = next.getNextException();
422-
}
423-
throw new StorageTransactionLogicException(throwables);
424-
}
425-
return null;
426-
});
410+
sqlCon.commit();
411+
} catch (SQLException throwables) {
412+
throw new StorageTransactionLogicException(throwables);
413+
}
427414
}
428415

429416
public static void deleteUser_Transaction(Connection sqlCon, Start start, AppIdentifier appIdentifier,
@@ -569,6 +556,30 @@ public static String lockEmail_Transaction(Start start, Connection con,
569556
});
570557
}
571558

559+
public static List<String> lockEmail_Transaction(Start start, Connection con,
560+
AppIdentifier appIdentifier,
561+
List<String> emails)
562+
throws StorageQueryException, SQLException {
563+
if(emails == null || emails.isEmpty()){
564+
return new ArrayList<>();
565+
}
566+
String QUERY = "SELECT user_id FROM " + getConfig(start).getEmailPasswordUsersTable() +
567+
" WHERE app_id = ? AND email IN (" + Utils.generateCommaSeperatedQuestionMarks(emails.size()) + ") FOR UPDATE";
568+
569+
return execute(con, QUERY, pst -> {
570+
pst.setString(1, appIdentifier.getAppId());
571+
for (int i = 0; i < emails.size(); i++) {
572+
pst.setString(2 + i, emails.get(i));
573+
}
574+
}, result -> {
575+
List<String> results = new ArrayList<>();
576+
while (result.next()) {
577+
results.add(result.getString("user_id"));
578+
}
579+
return results;
580+
});
581+
}
582+
572583
public static String getPrimaryUserIdUsingEmail(Start start, TenantIdentifier tenantIdentifier,
573584
String email)
574585
throws StorageQueryException, SQLException {
@@ -612,6 +623,33 @@ public static List<String> getPrimaryUserIdsUsingEmail_Transaction(Start start,
612623
});
613624
}
614625

626+
public static List<String> getPrimaryUserIdsUsingMultipleEmails_Transaction(Start start, Connection con,
627+
AppIdentifier appIdentifier,
628+
List<String> emails)
629+
throws StorageQueryException, SQLException {
630+
if(emails.isEmpty()){
631+
return new ArrayList<>();
632+
}
633+
String QUERY = "SELECT DISTINCT all_users.primary_or_recipe_user_id AS user_id "
634+
+ "FROM " + getConfig(start).getEmailPasswordUsersTable() + " AS ep" +
635+
" JOIN " + getConfig(start).getAppIdToUserIdTable() + " AS all_users" +
636+
" ON ep.app_id = all_users.app_id AND ep.user_id = all_users.user_id" +
637+
" WHERE ep.app_id = ? AND ep.email IN ( " + Utils.generateCommaSeperatedQuestionMarks(emails.size()) + " )";
638+
639+
return execute(con, QUERY, pst -> {
640+
pst.setString(1, appIdentifier.getAppId());
641+
for (int i = 0; i < emails.size(); i++) {
642+
pst.setString(2+i, emails.get(i));
643+
}
644+
}, result -> {
645+
List<String> userIds = new ArrayList<>();
646+
while (result.next()) {
647+
userIds.add(result.getString("user_id"));
648+
}
649+
return userIds;
650+
});
651+
}
652+
615653
public static boolean addUserIdToTenant_Transaction(Start start, Connection sqlCon,
616654
TenantIdentifier tenantIdentifier, String userId)
617655
throws SQLException, StorageQueryException, UnknownUserIdException {

0 commit comments

Comments
 (0)