diff --git a/src/main/java/io/supertokens/inmemorydb/Start.java b/src/main/java/io/supertokens/inmemorydb/Start.java index 919459a93..1fc7dfa90 100644 --- a/src/main/java/io/supertokens/inmemorydb/Start.java +++ b/src/main/java/io/supertokens/inmemorydb/Start.java @@ -2288,77 +2288,64 @@ public TenantConfig[] getAllTenants() throws StorageQueryException { } @Override - public boolean addUserIdToTenant_Transaction(TenantIdentifier tenantIdentifier, TransactionConnection conn, String userId) + public boolean addUserIdToTenant_Transaction(TenantIdentifier tenantIdentifier, TransactionConnection con, String userId) throws StorageQueryException, TenantOrAppNotFoundException, DuplicateEmailException, DuplicateThirdPartyUserException, DuplicatePhoneNumberException, UnknownUserIdException { + Connection sqlCon = (Connection) con.getConnection(); try { - return this.startTransaction(con -> { - Connection sqlCon = (Connection) con.getConnection(); - try { - String recipeId = GeneralQueries.getRecipeIdForUser_Transaction(this, sqlCon, tenantIdentifier, - userId); - - if (recipeId == null) { - throw new StorageTransactionLogicException(new UnknownUserIdException()); - } - - boolean added; - if (recipeId.equals("emailpassword")) { - added = EmailPasswordQueries.addUserIdToTenant_Transaction(this, sqlCon, tenantIdentifier, - userId); - } else if (recipeId.equals("thirdparty")) { - added = ThirdPartyQueries.addUserIdToTenant_Transaction(this, sqlCon, tenantIdentifier, userId); - } else if (recipeId.equals("passwordless")) { - added = PasswordlessQueries.addUserIdToTenant_Transaction(this, sqlCon, tenantIdentifier, - userId); - } else { - throw new IllegalStateException("Should never come here!"); - } + String recipeId = GeneralQueries.getRecipeIdForUser_Transaction(this, sqlCon, tenantIdentifier, + userId); - sqlCon.commit(); - return added; - } catch (SQLException throwables) { - throw new StorageTransactionLogicException(throwables); - } - }); - } catch (StorageTransactionLogicException e) { - if (e.actualException instanceof SQLException) { - SQLiteConfig config = Config.getConfig(this); - String serverErrorMessage = e.actualException.getMessage(); + if (recipeId == null) { + throw new UnknownUserIdException(); + } - if (isForeignKeyConstraintError( - serverErrorMessage, - config.getTenantsTable(), - new String[]{"app_id", "tenant_id"}, - new Object[]{tenantIdentifier.getAppId(), tenantIdentifier.getTenantId()})) { - throw new TenantOrAppNotFoundException(tenantIdentifier); - } - if (isUniqueConstraintError(serverErrorMessage, config.getEmailPasswordUserToTenantTable(), - new String[]{"app_id", "tenant_id", "email"})) { - throw new DuplicateEmailException(); - } - if (isUniqueConstraintError(serverErrorMessage, config.getThirdPartyUserToTenantTable(), - new String[]{"app_id", "tenant_id", "third_party_id", "third_party_user_id"})) { - throw new DuplicateThirdPartyUserException(); - } - if (isUniqueConstraintError(serverErrorMessage, - Config.getConfig(this).getPasswordlessUserToTenantTable(), - new String[]{"app_id", "tenant_id", "phone_number"})) { - throw new DuplicatePhoneNumberException(); - } - if (isUniqueConstraintError(serverErrorMessage, - Config.getConfig(this).getPasswordlessUserToTenantTable(), - new String[]{"app_id", "tenant_id", "email"})) { - throw new DuplicateEmailException(); - } + boolean added; + if (recipeId.equals("emailpassword")) { + added = EmailPasswordQueries.addUserIdToTenant_Transaction(this, sqlCon, tenantIdentifier, + userId); + } else if (recipeId.equals("thirdparty")) { + added = ThirdPartyQueries.addUserIdToTenant_Transaction(this, sqlCon, tenantIdentifier, userId); + } else if (recipeId.equals("passwordless")) { + added = PasswordlessQueries.addUserIdToTenant_Transaction(this, sqlCon, tenantIdentifier, + userId); + } else { + throw new IllegalStateException("Should never come here!"); + } - throw new StorageQueryException(e.actualException); - } else if (e.actualException instanceof UnknownUserIdException) { - throw (UnknownUserIdException) e.actualException; - } else if (e.actualException instanceof StorageQueryException) { - throw (StorageQueryException) e.actualException; + sqlCon.commit(); + return added; + } catch (SQLException throwables) { + SQLiteConfig config = Config.getConfig(this); + String serverErrorMessage = throwables.getMessage(); + + if (isForeignKeyConstraintError( + serverErrorMessage, + config.getTenantsTable(), + new String[]{"app_id", "tenant_id"}, + new Object[]{tenantIdentifier.getAppId(), tenantIdentifier.getTenantId()})) { + throw new TenantOrAppNotFoundException(tenantIdentifier); } - throw new StorageQueryException(e.actualException); + if (isUniqueConstraintError(serverErrorMessage, config.getEmailPasswordUserToTenantTable(), + new String[]{"app_id", "tenant_id", "email"})) { + throw new DuplicateEmailException(); + } + if (isUniqueConstraintError(serverErrorMessage, config.getThirdPartyUserToTenantTable(), + new String[]{"app_id", "tenant_id", "third_party_id", "third_party_user_id"})) { + throw new DuplicateThirdPartyUserException(); + } + if (isUniqueConstraintError(serverErrorMessage, + Config.getConfig(this).getPasswordlessUserToTenantTable(), + new String[]{"app_id", "tenant_id", "phone_number"})) { + throw new DuplicatePhoneNumberException(); + } + if (isUniqueConstraintError(serverErrorMessage, + Config.getConfig(this).getPasswordlessUserToTenantTable(), + new String[]{"app_id", "tenant_id", "email"})) { + throw new DuplicateEmailException(); + } + + throw new StorageQueryException(throwables); } } @@ -2804,13 +2791,12 @@ public AuthRecipeUserInfo getPrimaryUserById_Transaction(AppIdentifier appIdenti public AuthRecipeUserInfo[] listPrimaryUsersByEmail_Transaction(AppIdentifier appIdentifier, TransactionConnection con, String email) throws StorageQueryException { - return null; // TODO -// try { -// Connection sqlCon = (Connection) con.getConnection(); -// return GeneralQueries.listPrimaryUsersByEmail_Transaction(this, sqlCon, appIdentifier, email); -// } catch (SQLException e) { -// throw new StorageQueryException(e); -// } + try { + Connection sqlCon = (Connection) con.getConnection(); + return GeneralQueries.listPrimaryUsersByEmail_Transaction(this, sqlCon, appIdentifier, email); + } catch (SQLException e) { + throw new StorageQueryException(e); + } } @Override @@ -2818,14 +2804,13 @@ public AuthRecipeUserInfo[] listPrimaryUsersByPhoneNumber_Transaction(AppIdentif TransactionConnection con, String phoneNumber) throws StorageQueryException { - return null; // TODO -// try { -// Connection sqlCon = (Connection) con.getConnection(); -// return GeneralQueries.listPrimaryUsersByPhoneNumber_Transaction(this, sqlCon, tenantIdentifier, -// phoneNumber); -// } catch (SQLException e) { -// throw new StorageQueryException(e); -// } + try { + Connection sqlCon = (Connection) con.getConnection(); + return GeneralQueries.listPrimaryUsersByPhoneNumber_Transaction(this, sqlCon, appIdentifier, + phoneNumber); + } catch (SQLException e) { + throw new StorageQueryException(e); + } } @Override @@ -2842,14 +2827,13 @@ public AuthRecipeUserInfo[] listPrimaryUsersByThirdPartyInfo_Transaction(AppIden String thirdPartyId, String thirdPartyUserId) throws StorageQueryException { - return null; // TODO -// try { -// Connection sqlCon = (Connection) con.getConnection(); -// return GeneralQueries.getPrimaryUsersByThirdPartyInfo_Transaction(this, sqlCon, tenantIdentifier, -// thirdPartyId, thirdPartyUserId); -// } catch (SQLException e) { -// throw new StorageQueryException(e); -// } + try { + Connection sqlCon = (Connection) con.getConnection(); + return GeneralQueries.getPrimaryUsersByThirdPartyInfo_Transaction(this, sqlCon, appIdentifier, + thirdPartyId, thirdPartyUserId); + } catch (SQLException e) { + throw new StorageQueryException(e); + } } @Override diff --git a/src/main/java/io/supertokens/inmemorydb/queries/EmailPasswordQueries.java b/src/main/java/io/supertokens/inmemorydb/queries/EmailPasswordQueries.java index 77cb8f4ed..315ca7f44 100644 --- a/src/main/java/io/supertokens/inmemorydb/queries/EmailPasswordQueries.java +++ b/src/main/java/io/supertokens/inmemorydb/queries/EmailPasswordQueries.java @@ -397,19 +397,18 @@ public static List getUsersInfoUsingIdList(Start start, Connection return Collections.emptyList(); } - public static String lockEmailAndTenant_Transaction(Start start, Connection con, TenantIdentifier tenantIdentifier, - String email) throws SQLException, StorageQueryException { + public static String lockEmail_Transaction(Start start, Connection con, AppIdentifier appIdentifier, + String email) throws SQLException, StorageQueryException { // normally the query below will use a for update, but sqlite doesn't support it. ((ConnectionWithLocks) con).lock( - tenantIdentifier.getAppId() + tenantIdentifier.getTenantId() + "~" + email + - Config.getConfig(start).getEmailPasswordUserToTenantTable()); + appIdentifier.getAppId() + "~" + email + + Config.getConfig(start).getEmailPasswordUsersTable()); - String QUERY = "SELECT user_id FROM " + getConfig(start).getEmailPasswordUserToTenantTable() + - " WHERE app_id = ? AND tenant_id = ? AND email = ?"; + String QUERY = "SELECT user_id FROM " + getConfig(start).getEmailPasswordUsersTable() + + " WHERE app_id = ? AND email = ?"; return execute(con, QUERY, pst -> { - pst.setString(1, tenantIdentifier.getAppId()); - pst.setString(2, tenantIdentifier.getTenantId()); - pst.setString(3, email); + pst.setString(1, appIdentifier.getAppId()); + pst.setString(2, email); }, result -> { if (result.next()) { return result.getString("user_id"); @@ -439,6 +438,27 @@ public static String getPrimaryUserIdUsingEmail(Start start, Connection con, Ten }); } + public static List getPrimaryUserIdsUsingEmail(Start start, Connection con, AppIdentifier appIdentifier, + String email) + throws StorageQueryException, SQLException { + String QUERY = "SELECT DISTINCT all_users.primary_or_recipe_user_id AS user_id " + + "FROM " + getConfig(start).getEmailPasswordUsersTable() + " AS ep" + + " JOIN " + getConfig(start).getUsersTable() + " AS all_users" + + " ON ep.app_id = all_users.app_id AND ep.user_id = all_users.user_id" + + " WHERE ep.app_id = ? AND ep.email = ?"; + + return execute(con, QUERY, pst -> { + pst.setString(1, appIdentifier.getAppId()); + pst.setString(2, email); + }, result -> { + List userIds = new ArrayList<>(); + while (result.next()) { + userIds.add(result.getString("user_id")); + } + return userIds; + }); + } + public static boolean addUserIdToTenant_Transaction(Start start, Connection sqlCon, TenantIdentifier tenantIdentifier, String userId) throws SQLException, StorageQueryException { diff --git a/src/main/java/io/supertokens/inmemorydb/queries/GeneralQueries.java b/src/main/java/io/supertokens/inmemorydb/queries/GeneralQueries.java index 9b336371e..a3acdb0a8 100644 --- a/src/main/java/io/supertokens/inmemorydb/queries/GeneralQueries.java +++ b/src/main/java/io/supertokens/inmemorydb/queries/GeneralQueries.java @@ -917,21 +917,21 @@ public static void unlinkAccounts_Transaction(Start start, Connection sqlCon, Ap } public static AuthRecipeUserInfo[] listPrimaryUsersByPhoneNumber_Transaction(Start start, Connection sqlCon, - TenantIdentifier tenantIdentifier, + AppIdentifier appIdentifier, String phoneNumber) throws SQLException, StorageQueryException { // we first lock on the table based on phoneNumber and tenant - this will ensure that any other // query happening related to the account linking on this phone number / tenant will wait for this to finish, // and vice versa. - PasswordlessQueries.lockPhoneAndTenant_Transaction(start, sqlCon, tenantIdentifier, phoneNumber); + PasswordlessQueries.lockPhone_Transaction(start, sqlCon, appIdentifier, phoneNumber); // now that we have locks on all the relevant tables, we can read from them safely - return listPrimaryUsersByPhoneNumberHelper(start, sqlCon, tenantIdentifier, phoneNumber); + return listPrimaryUsersByPhoneNumberHelper(start, sqlCon, appIdentifier, phoneNumber); } - public static AuthRecipeUserInfo getPrimaryUsersByThirdPartyInfo_Transaction(Start start, Connection sqlCon, - TenantIdentifier tenantIdentifier, + public static AuthRecipeUserInfo[] getPrimaryUsersByThirdPartyInfo_Transaction(Start start, Connection sqlCon, + AppIdentifier appIdentifier, String thirdPartyId, String thirdPartyUserId) throws SQLException, StorageQueryException { @@ -940,29 +940,29 @@ public static AuthRecipeUserInfo getPrimaryUsersByThirdPartyInfo_Transaction(Sta // finish, // and vice versa. - ThirdPartyQueries.lockThirdPartyInfoAndTenant_Transaction(start, sqlCon, tenantIdentifier, thirdPartyId, + ThirdPartyQueries.lockThirdPartyInfo_Transaction(start, sqlCon, appIdentifier, thirdPartyId, thirdPartyUserId); // now that we have locks on all the relevant tables, we can read from them safely - return getPrimaryUserByThirdPartyInfoHelper(start, sqlCon, tenantIdentifier, thirdPartyId, thirdPartyUserId); + return listPrimaryUsersByThirdPartyInfoHelper(start, sqlCon, appIdentifier, thirdPartyId, thirdPartyUserId); } public static AuthRecipeUserInfo[] listPrimaryUsersByEmail_Transaction(Start start, Connection sqlCon, - TenantIdentifier tenantIdentifier, + AppIdentifier appIdentifier, String email) throws SQLException, StorageQueryException { // we first lock on the three tables based on email and tenant - this will ensure that any other // query happening related to the account linking on this email / tenant will wait for this to finish, // and vice versa. - EmailPasswordQueries.lockEmailAndTenant_Transaction(start, sqlCon, tenantIdentifier, email); + EmailPasswordQueries.lockEmail_Transaction(start, sqlCon, appIdentifier, email); - ThirdPartyQueries.lockEmailAndTenant_Transaction(start, sqlCon, tenantIdentifier, email); + ThirdPartyQueries.lockEmail_Transaction(start, sqlCon, appIdentifier, email); - PasswordlessQueries.lockEmailAndTenant_Transaction(start, sqlCon, tenantIdentifier, email); + PasswordlessQueries.lockEmail_Transaction(start, sqlCon, appIdentifier, email); // now that we have locks on all the relevant tables, we can read from them safely - return listPrimaryUsersByEmailHelper(start, sqlCon, tenantIdentifier, email); + return listPrimaryUsersByEmailHelper(start, sqlCon, appIdentifier, email); } public static AuthRecipeUserInfo[] listPrimaryUsersByEmail(Start start, TenantIdentifier tenantIdentifier, @@ -973,7 +973,7 @@ public static AuthRecipeUserInfo[] listPrimaryUsersByEmail(Start start, TenantId } } - private static AuthRecipeUserInfo[] listPrimaryUsersByEmailHelper(Start start, Connection con, + public static AuthRecipeUserInfo[] listPrimaryUsersByEmailHelper(Start start, Connection con, TenantIdentifier tenantIdentifier, String email) throws StorageQueryException, SQLException { @@ -1005,6 +1005,32 @@ private static AuthRecipeUserInfo[] listPrimaryUsersByEmailHelper(Start start, C return result.toArray(new AuthRecipeUserInfo[0]); } + public static AuthRecipeUserInfo[] listPrimaryUsersByEmailHelper(Start start, Connection con, + AppIdentifier appIdentifier, + String email) + throws StorageQueryException, SQLException { + List userIds = new ArrayList<>(); + userIds.addAll(EmailPasswordQueries.getPrimaryUserIdsUsingEmail(start, con, appIdentifier, + email)); + + userIds.addAll(PasswordlessQueries.getPrimaryUserIdsUsingEmail(start, con, appIdentifier, + email)); + + userIds.addAll(ThirdPartyQueries.getPrimaryUserIdUsingEmail(start, con, appIdentifier, email)); + + // remove duplicates from userIds + Set userIdsSet = new HashSet<>(userIds); + userIds = new ArrayList<>(userIdsSet); + + List result = getPrimaryUserInfoForUserIds(start, con, appIdentifier, + userIds); + + // this is going to order them based on oldest that joined to newest that joined. + result.sort(Comparator.comparingLong(o -> o.timeJoined)); + + return result.toArray(new AuthRecipeUserInfo[0]); + } + public static AuthRecipeUserInfo[] listPrimaryUsersByPhoneNumber(Start start, TenantIdentifier tenantIdentifier, String phoneNumber) @@ -1035,6 +1061,47 @@ private static AuthRecipeUserInfo[] listPrimaryUsersByPhoneNumberHelper(Start st return result.toArray(new AuthRecipeUserInfo[0]); } + + private static AuthRecipeUserInfo[] listPrimaryUsersByPhoneNumberHelper(Start start, Connection con, + AppIdentifier appIdentifier, + String phoneNumber) + throws StorageQueryException, SQLException { + List userIds = new ArrayList<>(); + + String passwordlessUserId = PasswordlessQueries.getPrimaryUserByPhoneNumber(start, con, appIdentifier, + phoneNumber); + if (passwordlessUserId != null) { + userIds.add(passwordlessUserId); + } + + List result = getPrimaryUserInfoForUserIds(start, con, appIdentifier, + userIds); + + // this is going to order them based on oldest that joined to newest that joined. + result.sort(Comparator.comparingLong(o -> o.timeJoined)); + + return result.toArray(new AuthRecipeUserInfo[0]); + } + + public static AuthRecipeUserInfo[] listPrimaryUsersByThirdPartyInfo(Start start, + AppIdentifier appIdentifier, + String thirdPartyId, + String thirdPartyUserId) + throws StorageQueryException, SQLException { + try (Connection con = ConnectionPool.getConnection(start)) { + return listPrimaryUsersByThirdPartyInfoHelper(start, con, appIdentifier, thirdPartyId, thirdPartyUserId); + } + } + + public static AuthRecipeUserInfo[] listPrimaryUsersByThirdPartyInfo_transaction(Start start, + Connection sqlCon, + AppIdentifier appIdentifier, + String thirdPartyId, + String thirdPartyUserId) + throws StorageQueryException, SQLException { + return listPrimaryUsersByThirdPartyInfoHelper(start, sqlCon, appIdentifier, thirdPartyId, thirdPartyUserId); + } + public static AuthRecipeUserInfo getPrimaryUserByThirdPartyInfo(Start start, TenantIdentifier tenantIdentifier, String thirdPartyId, @@ -1045,13 +1112,29 @@ public static AuthRecipeUserInfo getPrimaryUserByThirdPartyInfo(Start start, } } + private static AuthRecipeUserInfo[] listPrimaryUsersByThirdPartyInfoHelper(Start start, Connection con, + AppIdentifier appIdentifier, + String thirdPartyId, + String thirdPartyUserId) + throws StorageQueryException, SQLException { + + List userIds = ThirdPartyQueries.listUserIdsByThirdPartyInfo(start, con, appIdentifier, + thirdPartyId, thirdPartyUserId); + List result = getPrimaryUserInfoForUserIds(start, con, appIdentifier, userIds); + + // this is going to order them based on oldest that joined to newest that joined. + result.sort(Comparator.comparingLong(o -> o.timeJoined)); + + return result.toArray(new AuthRecipeUserInfo[0]); + } + private static AuthRecipeUserInfo getPrimaryUserByThirdPartyInfoHelper(Start start, Connection con, TenantIdentifier tenantIdentifier, String thirdPartyId, String thirdPartyUserId) throws StorageQueryException, SQLException { - String userId = ThirdPartyQueries.getThirdPartyUserInfoUsingId(start, con, tenantIdentifier, + String userId = ThirdPartyQueries.getUserIdByThirdPartyInfo(start, con, tenantIdentifier, thirdPartyId, thirdPartyUserId); if (userId != null) { return getPrimaryUserInfoForUserId(start, con, tenantIdentifier.toAppIdentifier(), @@ -1399,7 +1482,7 @@ private static class AllAuthRecipeUsersResultHolder { AllAuthRecipeUsersResultHolder(String userId, String tenantId, String primaryOrRecipeUserId, boolean isLinkedOrIsAPrimaryUser, String recipeId, long timeJoined) { - this.userId = userId; + this.userId = userId.trim(); this.tenantId = tenantId; this.primaryOrRecipeUserId = primaryOrRecipeUserId; this.isLinkedOrIsAPrimaryUser = isLinkedOrIsAPrimaryUser; diff --git a/src/main/java/io/supertokens/inmemorydb/queries/PasswordlessQueries.java b/src/main/java/io/supertokens/inmemorydb/queries/PasswordlessQueries.java index 82cd39bf9..c2c2a2aa0 100644 --- a/src/main/java/io/supertokens/inmemorydb/queries/PasswordlessQueries.java +++ b/src/main/java/io/supertokens/inmemorydb/queries/PasswordlessQueries.java @@ -736,42 +736,41 @@ public static UserInfoPartial getUserById(Start start, Connection sqlCon, AppIde }); } - public static String lockEmailAndTenant_Transaction(Start start, Connection con, TenantIdentifier tenantIdentifier, - String email) throws SQLException, StorageQueryException { + public static List lockEmail_Transaction(Start start, Connection con, AppIdentifier appIdentifier, + String email) throws SQLException, StorageQueryException { // normally the query below will use a for update, but sqlite doesn't support it. ((ConnectionWithLocks) con).lock( - tenantIdentifier.getAppId() + tenantIdentifier.getTenantId() + "~" + email + - Config.getConfig(start).getPasswordlessUserToTenantTable()); + appIdentifier.getAppId() + "~" + email + + Config.getConfig(start).getPasswordlessUsersTable()); - String QUERY = "SELECT user_id FROM " + getConfig(start).getPasswordlessUserToTenantTable() + - " WHERE app_id = ? AND tenant_id = ? AND email = ?"; + String QUERY = "SELECT user_id FROM " + getConfig(start).getPasswordlessUsersTable() + + " WHERE app_id = ? AND email = ?"; return execute(con, QUERY, pst -> { - pst.setString(1, tenantIdentifier.getAppId()); - pst.setString(2, tenantIdentifier.getTenantId()); - pst.setString(3, email); + pst.setString(1, appIdentifier.getAppId()); + pst.setString(2, email); }, result -> { - if (result.next()) { - return result.getString("user_id"); + List userIds = new ArrayList<>(); + while (result.next()) { + userIds.add(result.getString("user_id")); } - return null; + return userIds; }); } - public static String lockPhoneAndTenant_Transaction(Start start, Connection con, - TenantIdentifier tenantIdentifier, - String phoneNumber) + public static String lockPhone_Transaction(Start start, Connection con, + AppIdentifier appIdentifier, + String phoneNumber) throws SQLException, StorageQueryException { // normally the query below will use a for update, but sqlite doesn't support it. ((ConnectionWithLocks) con).lock( - tenantIdentifier.getAppId() + tenantIdentifier.getTenantId() + "~" + phoneNumber + - Config.getConfig(start).getPasswordlessUserToTenantTable()); + appIdentifier.getAppId() + "~" + phoneNumber + + Config.getConfig(start).getPasswordlessUsersTable()); - String QUERY = "SELECT user_id FROM " + getConfig(start).getPasswordlessUserToTenantTable() + - " WHERE app_id = ? AND tenant_id = ? AND phone_number = ?"; + String QUERY = "SELECT user_id FROM " + getConfig(start).getPasswordlessUsersTable() + + " WHERE app_id = ? AND phone_number = ?"; return execute(con, QUERY, pst -> { - pst.setString(1, tenantIdentifier.getAppId()); - pst.setString(2, tenantIdentifier.getTenantId()); - pst.setString(3, phoneNumber); + pst.setString(1, appIdentifier.getAppId()); + pst.setString(2, phoneNumber); }, result -> { if (result.next()) { return result.getString("user_id"); @@ -801,6 +800,27 @@ public static String getPrimaryUserIdUsingEmail(Start start, Connection con, Ten }); } + public static List getPrimaryUserIdsUsingEmail(Start start, Connection con, AppIdentifier appIdentifier, + String email) + throws StorageQueryException, SQLException { + String QUERY = "SELECT DISTINCT all_users.primary_or_recipe_user_id AS user_id " + + "FROM " + getConfig(start).getPasswordlessUsersTable() + " AS pless" + + " JOIN " + getConfig(start).getUsersTable() + " AS all_users" + + " ON pless.app_id = all_users.app_id AND pless.user_id = all_users.user_id" + + " WHERE pless.app_id = ? AND pless.email = ?"; + + return execute(con, QUERY, pst -> { + pst.setString(1, appIdentifier.getAppId()); + pst.setString(2, email); + }, result -> { + List userIds = new ArrayList<>(); + while (result.next()) { + userIds.add(result.getString("user_id")); + } + return userIds; + }); + } + public static String getPrimaryUserByPhoneNumber(Start start, Connection con, TenantIdentifier tenantIdentifier, @Nonnull String phoneNumber) throws StorageQueryException, SQLException { @@ -822,6 +842,26 @@ public static String getPrimaryUserByPhoneNumber(Start start, Connection con, Te }); } + public static String getPrimaryUserByPhoneNumber(Start start, Connection con, AppIdentifier appIdentifier, + @Nonnull String phoneNumber) + throws StorageQueryException, SQLException { + String QUERY = "SELECT DISTINCT all_users.primary_or_recipe_user_id AS user_id " + + "FROM " + getConfig(start).getPasswordlessUsersTable() + " AS pless" + + " JOIN " + getConfig(start).getUsersTable() + " AS all_users" + + " ON pless.app_id = all_users.app_id AND pless.user_id = all_users.user_id" + + " WHERE pless.app_id = ? AND pless.phone_number = ?"; + + return execute(con, QUERY, pst -> { + pst.setString(1, appIdentifier.getAppId()); + pst.setString(2, phoneNumber); + }, result -> { + if (result.next()) { + return result.getString("user_id"); + } + return null; + }); + } + public static boolean addUserIdToTenant_Transaction(Start start, Connection sqlCon, TenantIdentifier tenantIdentifier, String userId) throws StorageQueryException, SQLException { diff --git a/src/main/java/io/supertokens/inmemorydb/queries/ThirdPartyQueries.java b/src/main/java/io/supertokens/inmemorydb/queries/ThirdPartyQueries.java index 8a1fbef92..e38b6b336 100644 --- a/src/main/java/io/supertokens/inmemorydb/queries/ThirdPartyQueries.java +++ b/src/main/java/io/supertokens/inmemorydb/queries/ThirdPartyQueries.java @@ -185,25 +185,21 @@ public static void deleteUser_Transaction(Connection sqlCon, Start start, AppIde } } - public static List lockEmailAndTenant_Transaction(Start start, Connection con, - TenantIdentifier tenantIdentifier, + public static List lockEmail_Transaction(Start start, Connection con, + AppIdentifier appIdentifier, String email) throws SQLException, StorageQueryException { // normally the query below will use a for update, but sqlite doesn't support it. ((ConnectionWithLocks) con).lock( - tenantIdentifier.getAppId() + tenantIdentifier.getTenantId() + "~" + email + - Config.getConfig(start).getThirdPartyUserToTenantTable()); + appIdentifier.getAppId() + "~" + email + + Config.getConfig(start).getThirdPartyUsersTable()); - // in psql / mysql dbs, this will lock the rows that are in both the tables that meet the ON criteria only. String QUERY = "SELECT tp.user_id as user_id " + "FROM " + getConfig(start).getThirdPartyUsersTable() + " AS tp" + - " JOIN " + getConfig(start).getThirdPartyUserToTenantTable() + " AS tp_tenants" + - " ON tp_tenants.app_id = tp.app_id AND tp_tenants.user_id = tp.user_id" + - " WHERE tp.app_id = ? AND tp_tenants.tenant_id = ? AND tp.email = ?"; + " WHERE tp.app_id = ? AND tp.email = ?"; return execute(con, QUERY, pst -> { - pst.setString(1, tenantIdentifier.getAppId()); - pst.setString(2, tenantIdentifier.getTenantId()); - pst.setString(3, email); + pst.setString(1, appIdentifier.getAppId()); + pst.setString(2, email); }, result -> { List finalResult = new ArrayList<>(); while (result.next()) { @@ -213,25 +209,24 @@ public static List lockEmailAndTenant_Transaction(Start start, Connectio }); } - public static List lockThirdPartyInfoAndTenant_Transaction(Start start, Connection con, - TenantIdentifier tenantIdentifier, - String thirdPartyId, String thirdPartyUserId) + public static List lockThirdPartyInfo_Transaction(Start start, Connection con, + AppIdentifier appIdentifier, + String thirdPartyId, String thirdPartyUserId) throws SQLException, StorageQueryException { // normally the query below will use a for update, but sqlite doesn't support it. ((ConnectionWithLocks) con).lock( - tenantIdentifier.getAppId() + tenantIdentifier.getTenantId() + "~" + thirdPartyId + thirdPartyUserId + - Config.getConfig(start).getThirdPartyUserToTenantTable()); + appIdentifier.getAppId() + "~" + thirdPartyId + thirdPartyUserId + + Config.getConfig(start).getThirdPartyUsersTable()); // in psql / mysql dbs, this will lock the rows that are in both the tables that meet the ON criteria only. String QUERY = "SELECT user_id " + - " FROM " + getConfig(start).getThirdPartyUserToTenantTable() + - " WHERE app_id = ? AND tenant_id = ? AND third_party_id = ? AND third_party_user_id = ?"; + " FROM " + getConfig(start).getThirdPartyUsersTable() + + " WHERE app_id = ? AND third_party_id = ? AND third_party_user_id = ? FOR UPDATE"; return execute(con, QUERY, pst -> { - pst.setString(1, tenantIdentifier.getAppId()); - pst.setString(2, tenantIdentifier.getTenantId()); - pst.setString(3, thirdPartyId); - pst.setString(4, thirdPartyUserId); + pst.setString(1, appIdentifier.getAppId()); + pst.setString(2, thirdPartyId); + pst.setString(3, thirdPartyUserId); }, result -> { List finalResult = new ArrayList<>(); while (result.next()) { @@ -271,7 +266,30 @@ public static List getUsersInfoUsingIdList(Start start, Connection return Collections.emptyList(); } - public static String getThirdPartyUserInfoUsingId(Start start, Connection con, TenantIdentifier tenantIdentifier, + public static List listUserIdsByThirdPartyInfo(Start start, Connection con, AppIdentifier appIdentifier, + String thirdPartyId, String thirdPartyUserId) + throws SQLException, StorageQueryException { + + String QUERY = "SELECT DISTINCT all_users.primary_or_recipe_user_id AS user_id " + + "FROM " + getConfig(start).getThirdPartyUsersTable() + " AS tp" + + " JOIN " + getConfig(start).getUsersTable() + " AS all_users" + + " ON tp.app_id = all_users.app_id AND tp.user_id = all_users.user_id" + + " WHERE tp.app_id = ? AND tp.third_party_id = ? AND tp.third_party_user_id = ?"; + + return execute(con, QUERY, pst -> { + pst.setString(1, appIdentifier.getAppId()); + pst.setString(2, thirdPartyId); + pst.setString(3, thirdPartyUserId); + }, result -> { + List userIds = new ArrayList<>(); + while (result.next()) { + userIds.add(result.getString("user_id")); + } + return userIds; + }); + } + + public static String getUserIdByThirdPartyInfo(Start start, Connection con, TenantIdentifier tenantIdentifier, String thirdPartyId, String thirdPartyUserId) throws SQLException, StorageQueryException { String QUERY = "SELECT DISTINCT all_users.primary_or_recipe_user_id AS user_id " @@ -293,6 +311,27 @@ public static String getThirdPartyUserInfoUsingId(Start start, Connection con, T }); } + public static List getPrimaryUserIdUsingEmail(Start start, Connection con, + AppIdentifier appIdentifier, String email) + throws StorageQueryException, SQLException { + String QUERY = "SELECT DISTINCT all_users.primary_or_recipe_user_id AS user_id " + + "FROM " + getConfig(start).getThirdPartyUsersTable() + " AS tp" + + " JOIN " + getConfig(start).getUsersTable() + " AS all_users" + + " ON tp.app_id = all_users.app_id AND tp.user_id = all_users.user_id" + + " WHERE tp.app_id = ? AND tp.email = ?"; + + return execute(con, QUERY, pst -> { + pst.setString(1, appIdentifier.getAppId()); + pst.setString(2, email); + }, result -> { + List finalResult = new ArrayList<>(); + while (result.next()) { + finalResult.add(result.getString("user_id")); + } + return finalResult; + }); + } + public static void updateUserEmail_Transaction(Start start, Connection con, AppIdentifier appIdentifier, String thirdPartyId, String thirdPartyUserId, String newEmail) throws SQLException, StorageQueryException {